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

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

### 環境
- **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で開発されたもの](https://library.naist.jp/dspace/handle/10061/4365)であり、Linux 2.6.38でカーネルにマージされました。
> USB/IP プロジェクトは IP ネットワーク上で汎用の USB デバイス共有システムを開発することを目的としている。コンピュータ間で USB デバイスを共有するために、USB/IP は "USB I/O メッセージ" を TCP/IP ペイロードにカプセル化してコンピュータ間で通信する。
[ArchWiki](https://wiki.archlinux.jp/index.php/USB/IP)


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

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

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



---
# セットアップ
初回のみ実行する必要があります。

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

```sh
$ sudo apt install usbip
```



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

```sh
$ sudo ufw allow 3240/tcp 
$ sudo ufw enable
$ sudo ufw reload
```
USP/IPはlinux-tools-genericというパッケージ内にあるのでaptを使ってインストールします。

```sh
$ 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することでデバイスが切断されたように見えます。

```sh
$ ​sudo modprobe usbip_host
$ usbip list -l
```
カーネルモジュールのloadと、bindしたいデバイスのbusid(ここでは`?????`)を調べます。

```sh
$ sudo usbip bind -b ?????
$ sudo usbipd -D
```
busidを指定してbindします。次に、デーモンを起動します。
### unbind
clientでdetach(詳細は後述)してからbindを解除します。

```sh
$ sudo usbip unbind -b ?????
```

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

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

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

```sh
$ 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補完で入力できます。



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

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

```sh
$ /usr/lib/linux-tools/$(uname -r)/usbip port
```
detachしたいデバイスのport(`??`)を調べます。

```sh
$ sudo /usr/lib/linux-tools/$(uname -r)/usbip detach -p ??
```
portを指定してdetachを行います。

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

---


# 参考
- https://library.naist.jp/dspace/handle/10061/4365
- https://developer.ridgerun.com/wiki/index.php?title=How_to_setup_and_use_USB/IP
- https://discourse.osmc.tv/t/testing-usb-ip/70554/2
- https://wiki.archlinux.jp/index.php/USB/IP