:wq!

Raspberry Pi Zero 2台とB+をUSBで繋いでLinuxルーター検証環境を作る

ども、takiponeです。この記事は Raspberry Pi Advent Calendar 2020 - Adventar の12/15分です。

Linux netfilter(iptables)の検証のために、2つのネットワークセグメントとそれぞれに接続する2つのLinuxノード、それを中継するLinuxルーターを組めないかなと手元のRaspberry Piで作ってみました。

ポイントはRaspebrry Pi ZeroのUSB OTG機能によってスイッチやLANケーブルなどのネットワーク機材を使わず、USBケーブル1本でルーターとノードをつなげている点です。電源供給と有線LANを兼ねている様子はAmazon EC2 MacインスタンスのThunderbolt接続を彷彿とさせませんか(しない)。ネットワーク構成は以下にしてみました。

動作確認環境

  • ハードウェア
    • Raspberry Pi Zero W
    • Raspberry Pi Zero WH
    • Raspberry Pi 4 Model B
  • ソフトウェア
    • Raspberry Pi OS Lite 32bit 2020-12-02

手順

Raspberry Pi Zero(Linuxノード)のセットアップ

まずはRaspberry Pi Zeroの初期設定をまとめて行うスクリプトを作成しました。

Raspberry Pi OSのイメージをMicro SDカードに書き込み、一度差し直したらスクリプトを実行します。

#!/bin/bash

MOUNTPOINT=/Volumes/boot
SEDCMD=gsed

if [ ! -d $MOUNTPOINT ]
then
  echo "Error: SD Card isn't mounted."
  exit 1
fi

cd $MOUNTPOINT
touch ssh
echo 'country=JP
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
network={
    ssid="YOUR_SSID"
    psk="YOUR_PASSWORD"
}' > wpa_supplicant.conf
echo 'dtoverlay=dwc2' >> config.txt
$SEDCMD -i 's/rootwait/rootwait modules-load=dwc2,g_ether/' cmdline.txt
cd
sudo umount $MOUNTPOINT

echo 'Done'
exit 0

Micro SDカードをセットしてRaspberry Pi 4B(Linuxルーター)と接続すると電源が入り起動します。Wi-Fi経由でログインするとUSBのネットワーク接続はインターフェース名 usb0 で認識されます。

pizero1$ ip addr show usb0
2: usb0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 0a:2c:ce:d9:c8:7e brd ff:ff:ff:ff:ff:ff
    inet 169.254.146.203/16 brd 169.254.255.255 scope global noprefixroute usb0
       valid_lft forever preferred_lft forever
    inet6 fe80::6f22:7dd3:dcce:1b90/64 scope link
       valid_lft forever preferred_lft forever

zeroconfのリンクローカルアドレスが見えますね。今回は任意のIPアドレスを振りたいので、 ip コマンドで設定しました。

pizero1$ sudo ip addr add 10.128.10.1/27 dev usb0
pizero1$ ip addr show usb0
2: usb0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 0a:2c:ce:d9:c8:7e brd ff:ff:ff:ff:ff:ff
    inet 169.254.146.203/16 brd 169.254.255.255 scope global noprefixroute usb0
       valid_lft forever preferred_lft forever
    inet 10.128.10.1/27 scope global usb0
       valid_lft forever preferred_lft forever
    inet6 fe80::6f22:7dd3:dcce:1b90/64 scope link
       valid_lft forever preferred_lft forever

pizero2側のセグメントのルーティングを追加します。

pizero1$ sudo ip route add 10.128.20.0/27 via 10.128.10.2
pizero1$ sudo ip route
default via 192.168.3.1 dev wlan0 proto dhcp src 192.168.3.56 metric 303
10.128.10.0/27 dev usb0 proto kernel scope link src 10.128.10.1
10.128.20.0/27 via 10.128.10.2 dev usb0
169.254.0.0/16 dev usb0 scope link src 169.254.146.203 metric 202
192.168.3.0/24 dev wlan0 proto dhcp scope link src 192.168.3.56 metric 303

これでOKです。 pizero2も同様にIPアドレス 10.128.20.1/27 を振って 10.128.10.0/27 のルーティングを 10.128.20.2 に向けます。

Raspberry Pi 4B(Linuxルーター)のセットアップ

Raspberry Pi 4B(Linuxルーター)側のRaspberry Pi ZeroとのUSB接続はホットプラグで自動認識されるため、OTGの設定は不要です。接続順にインターフェース名 usb0usb1 と振られて行くので、どちらのRaspberry Pi Zeroとの接続なのかわからなくならないように注意しましょう。

pirouter$ sudo ip addr add 10.128.10.2/27 dev usb0
pirouter$ sudo ip addr add 10.128.20.2/27 dev usb1

あとはIP転送を有効にすればルーターとして機能します。

pirouter$ sudo sysctl net.ipv4.ip_forward=1
net.ipv4.ip_forward = 1

では、pizero1からpizero2にpingしてみます。

pizero1$ ping 10.128.20.1
PING 10.128.20.1 (10.128.20.1) 56(84) bytes of data.
64 bytes from 10.128.20.1: icmp_seq=1 ttl=63 time=0.905 ms
64 bytes from 10.128.20.1: icmp_seq=2 ttl=63 time=0.834 ms
64 bytes from 10.128.20.1: icmp_seq=3 ttl=63 time=0.821 ms
64 bytes from 10.128.20.1: icmp_seq=4 ttl=63 time=0.842 ms
64 bytes from 10.128.20.1: icmp_seq=5 ttl=63 time=0.916 ms
^C
--- 10.128.20.1 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 10ms
rtt min/avg/max/mdev = 0.821/0.863/0.916/0.050 ms

pirouter経由でpingが返ってきました!

あとがき

VirtualBoxやESXiでサクッと作れると言えば作れるので、パケットを銅線に通したい願望に応える趣味の構成ですね。

参考URL