1

I am looking to have a host start up and run usbip

[Unit]
Description=USB-IP Binding
After=network-online.target

[Service]
ExecStartPre=/usr/sbin/usbipd -D
ExecStart=/usr/sbin/usbip bind --busid 1-1.5
ExecStop=/usr/sbin/usbip unbind --busid 1-1.5
Restart=on-failure  

[Install]
WantedBy=default.target

It appears to start correctly with out error, but when i go to the client and list the server it does not show that usbip running.

Also does anyone know of a script to share all USB device via USBIP.

Thank you for the help.

2
  • Check the process ID of the usbipd process: does it keep changing or stay the same once you've started your service? Your service might expect the usbip bind command to keep running forever, and I'm not sure that's how it actually works. Also, if you have any sort of iptables firewalling configured, have you allowed access to TCP port 3240 of the server host from the client host?
    – telcoM
    Jul 7, 2019 at 10:52
  • Thank you for the reply. I was able to find out a way to get it work, see link below. community.home-assistant.io/t/…
    – demslam
    Jul 8, 2019 at 18:32

2 Answers 2

4

Based on the link OP posted in the comments, the problem seems to have been here:

ExecStartPre=/usr/sbin/usbipd -D
ExecStart=/usr/sbin/usbip bind --busid 1-1.5

If you don't specify a Type= option for a systemd service, it assumes the service is of Type=simple. In that case, systemd will assume that the process started with the ExecStart= option will run forever if all is well. But the usbip bind command just tells the usbipd process to take over the service, and then exits. Then systemd will think "Oh no, the service has crashed!", and since it also has Restart=on-failure, it will keep restarting the service, over and over and over.

To make it work, you might specify Type=forking and make the actual usbipd process be the ExecStart= line, and usbip bind be an ExecStartPost= line, as suggested in the link you posted. But that solution has a mistake that is typical to new users of systemd: you're assuming that usbipd needs to become a daemon process on its own, while systemd can easily do it for you.

The best solution is to remove the -D option from the usbipd command line, and omit the Type=forking (or use Type=simple explicitly). This way, systemd will deal with the daemonization for you, and will also be able to monitor and stop the service process without resorting to PID files or haphazard killall usbipd ExecPost= commands.

So, what I'd recommend is:

[Unit]
Description=USB-IP Binding
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
ExecStart=/usr/sbin/usbipd
ExecStartPost=/usr/sbin/usbip bind --busid 1-1.5
ExecStop=/usr/sbin/usbip unbind --busid 1-1.5  

[Install]
WantedBy=multi-user.target

With these settings, systemd will expect that the usbipd process will run forever, and will in fact mark the service as failed if the process dies unexpectedly. You could add Restart=on-failure, if you want the systemd to automatically restart the service in that case.

When shutting down the service, the ExecStop command will tell usbipd to cleanly unbind from the USB device, and once that's successfully done, systemd will see that the server process is still running, and will kill it without any explicit command.

Whenever you use After=network-online.target, you should always also use Wants=network-online.target, or else it might not work as expected. See Running Services after the Network is Up in systemd documentation, which is also referred to in the man page covering the systemd special targets, systemd.special(7).

3

The approach I took was to break this in to two services, one for the daemon and a template for the binds.

So for the daemon - /etc/systemd/system/usbipd.service

[Unit]
Description=usbip host daemon
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
Restart=always
ExecStartPre=/usr/sbin/modprobe usbip-core
ExecStartPre=/usr/sbin/modprobe usbip-host
ExecStart=/usr/sbin/usbipd
ExecStopPost=/usr/sbin/rmmod usbip-host
ExecStopPost=/usr/sbin/rmmod usbip-core

[Install]
WantedBy=multi-user.target

And the template for the binds - /etc/systemd/system/[email protected]

[Unit]
Description=Bind USB device to usbipd
After=network-online.target usbipd.service
Wants=network-online.target usbipd.service

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/sbin/usbip bind --busid %i
ExecStop=/usr/sbin/usbip unbind --busid %i

[Install]
WantedBy=multi-user.target

Enable and start the daemon with:

systemctl enable usbipd
systemctl start usbuipd

Then add binds with:

systemctl enable [email protected]
systemctl start [email protected]

Replace 1-1.2.3 with the bind id of the USB device you want to share. You can use as many of these as devices you want to share and you can then bind and unbind each one individually and have then bind at machine startup (or not).

Find the bind ids with:

usbip list -l

Note that usbip binds seem to expire if not attached by a remote machine within around 10 mins - not very helpful!

I haven't yet decided how I'm going to tackle the client attach, possibly not with systemd. It would be really helpful if usbip had a bit more intelligence...

1
  • Nice approach here. For the client-side attaches, since I wanted full automation, I settled on performing them via Consul watches/handlers. Whenever the server binds any of its devices, the local consul agent writes a small update to Consul for the corresponding IP and bus ID for that device; the consul agent on the client has watches set for each of the devices it needs, so when there's any change written to one of those, the handler script performs the attach for that device. So while it does require a small Consul setup, it's relatively low-hassle to get going (and single-binary goodness). Apr 13, 2021 at 3:23

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .