👏

Raspberry piを使ってUSBデバイスサーバを作る(USB/IP)

2021/10/03に公開

はじめに

USB/IP(universal serial bus extension over IP network)を使って無料(ライセンス料無し)で複数個のUSBデバイスをネットワーク共有する手法についての記事です。

環境

  • server : Raspbian GUN/Linux 10, Raspberry Pi 3 Model B
  • client : Ubuntu 18.04.05 LTS

TL;DR

Raspberry piのUSB端子に接続したデバイスの通信を有線LANを介することで、ネットワーク上の他のPCに接続したかのように振舞わせることができます。


やりたいことのイメージ

USB over Ethernetを実現します。
Raspberry piでUSBデバイスサーバを立てます。
Raspberry piにUSBメモリなどのデバイスを接続し、その情報のやり取りを他のPCとの間で有線LAN経由で行います。

USB/IPとは

USB/IPとは、USBデバイスをIPネットワーク上で共有しようというプロジェクトの成果物です。
2007年ごろにNAISTで開発されたものであり、Linux 2.6.38でカーネルにマージされました。

USB/IP プロジェクトは IP ネットワーク上で汎用の USB デバイス共有システムを開発することを目的としている。コンピュータ間で USB デバイスを共有するために、USB/IP は "USB I/O メッセージ" を TCP/IP ペイロードにカプセル化してコンピュータ間で通信する。
ArchWiki

類似の手法など

類似の手法としては、VirtualHere、製品としては、IO-DATA社のnet.USBなどがあります。

  • VirtualHere ソフトウェア。同時使用できる数は無料版では1デバイスまで。追加でネットワークに接続するには1デバイスにつき約$50のライセンス料を払わないと複数個のデバイスを共有できない。セットアップは非常に簡単なので共有するデバイスが1つだけの場合はこちらの方でも良い。linux対応。
  • net.USB ネットワーク共有するための製品。linux非対応。

というわけで今回は、linux対応かつお金のかからないオープンな技術でトライしてみます。


セットアップ

初回のみ実行する必要があります。

Raspberry piでのserverのセットアップ

Raspberry piで行うべき設定。
Raspberry pi側の設定はIPの固定をします。
「raspberry pi ip 固定」などで検索すれば解説が多数あるので省略。
続いて、usbipをaptでインストールしておきます。

$ sudo apt install usbip

Ubuntu18.04でのclientのセットアップ

Ubuntuで行うべき設定。
USB/IPは予め3240番のポートを開放しておく必要があります。ufwを使ってポート開放を行います。

$ sudo ufw allow 3240/tcp 
$ sudo ufw enable
$ sudo ufw reload

USP/IPはlinux-tools-genericというパッケージ内にあるのでaptを使ってインストールします。

$ sudo apt install hwdata linux-tools-generic

使い方

デバイスを接続するにはserver(Raspberry pi)でbindしてからclient(Ubuntu)でattachします。
取り外すにはclientでdetachしてからserverでunbindします。
???の部分は環境によって異なる。(ex.1-1.2)というように記述されていそうな例を示しています。

用語の説明

bind : server側で共有できるようにすること。serverから見たとき、bindするとデバイスが切り離されたように見える。
attach : 共有可能な状態になっている(bindされている)デバイスをclient側でマウントすること。
detach : attachしたデバイスをアンマウントすること。detachするデバイスはportを確認し、portを指定して行う(やり方は後述)。


server(Raspberry pi側)で普段使うコマンド

以下にRaspberry pi側で実行が必要なコマンドを示します。
今回、Raspberry piのIPアドレスは192.168.0.111に固定しています。

bind

server(Raspberry pi)側で共有できるようにします。serverから見たとき、bindすることでデバイスが切断されたように見えます。

$ ​sudo modprobe usbip_host
$ usbip list -l

カーネルモジュールのloadと、bindしたいデバイスのbusid(ここでは?????)を調べます。

$ sudo usbip bind -b ?????
$ sudo usbipd -D

busidを指定してbindします。次に、デーモンを起動します。

unbind

clientでdetach(詳細は後述)してからbindを解除します。

$ sudo usbip unbind -b ?????

server(Raspberry pi側)で普段使うコマンドおわり。

client(PC側)で普段使うコマンド

以下にUbuntu(PC)側で実行が必要なコマンドを示します。

attach

共有可能な状態になっている(bindされている)デバイスをclient側でマウントします。

$ sudo modprobe vhci-hcd
$ /usr/lib/linux-tools/$(uname -r)/usbip list -r 192.168.0.111

ここで、192.168.0.111は各自任意に設定したRaspberry piのIPアドレスです。適宜置き換えてください。
カーネルモジュールのloadと、bindしたいデバイスのbusid(=?????)を調べます。
pathの$(uname -r)はtab補完で入力できます。

$ sudo /usr/lib/linux-tools/$(uname -r)/usbip attach -r 192.168.0.111 -b ?????(ex.1-1.2)

detach

attachしたデバイスをアンマウントします。detachするデバイスはportを確認し、portを指定して行います。

$ /usr/lib/linux-tools/$(uname -r)/usbip port

detachしたいデバイスのport(??)を調べます。

$ sudo /usr/lib/linux-tools/$(uname -r)/usbip detach -p ??

portを指定してdetachを行います。

client(PC側)で普段使うコマンドおわり。


余談

最後のコマンドについて、/usr/lib..../usbipまでの部分はlnコマンドで省略すると使いやすいかもしれません。

参考

Discussion