Raspberry Piでネットワークエミュレータ機能付きWLANブリッジを作る

## 概要

スマホなど無線ネットワークにつながる機器に向けて映像・音声などメディアを扱うアプリの開発を行うときに、ネットワーク上のパケットロスやジッターなどがある貧弱なネットワーク環境を作ってテストしたい場合があります。

そんなときには、スマホとLANの間にネットワークエミュレータと無線LANブリッジを挟めば、貧弱なネットワーク環境を意図的に作り出してテストすることができます。

```figure
        +------------------+     +-------------+
LAN === | Network Emulator | === | WLAN Bridge | ... Smartphone
        +------------------+     +-------------+

   === : Ether cable
   ... : Wifi connection
```

ネットワークエミュレータと無線LANブリッジはそれぞれ別の機器として用意するのが一般的と思いますが、Raspberry Piが１台あれば、この２つの役割をもたせたネットワークエミュレーション機能付きの無線LANブリッジを構成することができます。

```figure
        +---------------------------+
LAN === | Raspbery pi WLAN Bridge   | ... Smartphone
        |   with network emulator.  |
        +---------------------------+
```



## 用意するもの

Raspberry Pi3 または Pi4を用意します。ここでは、Raspberry Pi4を使って作成しましたが、Raspberry Pi3でも同じ方法で作成できると思います。

## 作成の手順

### OSをインストールする

"Raspberry Pi Imager"を使ってRaspberry Pi OSがインストールされたSDカードを作成します。

ここでは、Raspberry piをヘッドレスでSSHでリモートから制御することを想定して、デスクトップ環境が無い「RASPBERRY PI OS LITE(32-BIT)」を選択します。

書き込みが終わったら一旦SDカードを抜いて再び書き込みをしたMac(or PC)に接続して認識させます。

SD-Cardの`/boot`フォルダに"ssh"という名前で空のファイルを作成します。これによりRaspberry piが起動直後からSSHが有効化されSSHでパスワードでログインできるようになります。Macであれば以下のコマンドで`/boot`フォルダにからファイルが作成できます。

```console
touch /Volumes/boot/ssh
```

SDカードを"取り出し"てRaspberry piに差し込んで電源をつないで起動させます。このときに、有線LANも接続しておきます。

起動したらsshでユーザ名とRaspberry piのアドレス、パスワードを入れてログインします。初期のユーザ名は"pi"、パスワードは"raspberry"です。IPアドレスは、一旦、ディスプレイとキーボードを接続して取得する方法か、または、ルータのDHCPリース情報から取得する手段があります。

```
ssh pi@<IP Addres>
password:
```

ログインできたらパスワードを変更しておきましょう。.sshにリモートのパブリックキーを設定してパスワード入力なしでログインできるようにするのも良いでしょう。



### ネットワークブリッジとして設定する

無線LANブリッジ化に必要なパッケージをインストールします。

```raspberry pi
sudo apt update
sudo apt install -y bridge-utils hostapd
```

`/etc/netowork/interfaces` ファイルに以下を追加します。

```/etc/network/interfaces
auto br0
iface br0 inet dhcp
bridge_ports eth0 wlan0
```

`/etc/hostapd/hostapd.conf`ファイルを以下のように記述します。一番下の２行はアクセスポイントとして動作するときの「SSID」と「WLAN」パスワードを記述します。

```/etc/hostapd/hostapd.conf
interface=wlan0
bridge=br0
driver=nl80211
hw_mode=b
channel=1
macaddr_acl=0
auth_algs=1
ignore_broadcast_ssid=0
ieee80211ac=0
wmm_enabled=1
ieee80211d=1
country_code=JP
ieee80211h=1
local_pwr_constraint=3
spectrum_mgmt_required=1
wpa=3
wpa_key_mgmt=WPA-PSK
ssid=raspi_bridge
wpa_passphrase=********
```



`/etc/default/hostapd`ファイルを編集して、「#DAEMON_CONF=""」の行を、以下のように変更します。。

```/etc/default/hostapd
DAEMON_CONF="/etc/hostapd/hostapd.conf"
```

hostapdサービスを自動起動するように設定します。

```raspberry pi
sudo systemctl unmask hostapd
sudo systemctl enable hostapd
sudo systemctl start hostapd

```

WLANがsoft blockされているので使えるようにします。

```raspberry pi
sudo rfkill unblock 0

```

Raspberry piを再起動します。

以上でRaspberry PiがWLANブリッジとして設定が完了して、動作を開始します。

試しに他のデバイスを`/etc/hostapd/hostapd.conf`ファイルで設定したアクセスポイント名に接続して動作を確認しましょう。

### ネットワークエミュレーション機能を設定する

遅延や、パケットロスなどのネットワークエミュレーション機能を使うには「tc コマンド」を使うのですが、標準で使えるようになっているので特に追加インストールの必要はありません。

## 使い方

tcコマンドには色々な機能と使用方法があるようですが、ここではパケットロスと遅延＆ジッターをエミュレーションする方法のみを説明します。tcコマンドは`sudo`を使ってルート権限で起動します。ネットワークエミュレーションは、無線LANから有線LANへのパケット送信、またはその逆に、有線LANから無線LANへの送信のそれぞれに設定することができます。

### 無線LANから有線LANへのパケットの送信にネットワークエミュレータを設定する

#### 準備

初めに、wlan0 --> eth0の通信にネットワークエミュレータを追加します。devの後ろに有線LANのデバイス名'eth0'を指定していますが、これは'eth0'から出ていくパケットにネットワークエミュレーションを追加することを意味しています。

```
sudo tc qdisc add dev eth0 root netem
```

#### 遅延の設定

ネットワークエミュレータの遅延を100msに設定変更します。

```
sudo tc qdisc change dev eth0 root netem delay 100ms 
```

#### ジッターの設定

ネットワークエミュレータの遅延を100ms、ジッターを±50msに設定変更します。

```
sudo tc qdisc change dev eth0 root netem delay 100ms 50ms
```

#### パケットロスの設定

ネットワークエミュレータをパケットロス5%を発生するように設定変更します。

```
sudo tc qdisc change dev eth0 root netem loss 5%
```

#### 削除

ネットワークエミュレータを削除します。

```
sudo tc qdisc del dev eth0 root 
```

### 有線LANから無線LANへのパケットの送信にネットワークエミュレータを設定する

eth0 --> wlanの通信にネットワークエミュレータを追加設定するときは、devの後の`eth0`を`wlan0`に置き換えます。

```
# 準備（ネットワークエミュレーションの追加）
sudo tc qdisc add dev wlan0 root netem   
# 遅延の設定
sudo tc qdisc change dev wlan0 root netem delay 100ms
# ジッターの設定
sudo tc qdisc change dev wlan0 root netem delay 100ms 50ms
# パケットロスの設定
sudo tc qdisc change dev wlan0 root netem loss 5%
# 削除
sudo tc qdisc del dev wlan0 root
```



## 検証

### パケットロスとジッターの検証例

本当にパケットロスやジッターが狙ったとおり付加されているかを、ネットワークの品質測定ツールである"iPerf3"を使って実測して検証することができます。

### iperf3のインストール

iperf3のubuntuへのインストール方法は、

```
sudo apt update
sudo apt install iperf3
```

iperf3のmacへインストール方法は、brewコマンドが使えるようになっていれば以下のとおりです。

```
brew update
brew install iperf3
```

### 検証環境

```
+---------------+         +---------------------+          +---------------+
| PC(Ubuntu)    | ======= | Raspberry pi Bridge | ........ |       Mac     |
| iperf3 Server |   LAN   |   network emulator  |   Wifi   | iperf3 Client |
+---------------+         +---------------------+          +---------------+ 
```

Macをラズパイブリッジ経由でLANに接続しLAN上のUbuntu PCとの間の通信品質をiperf3で測定します。

PC(Ubuntu)側でiperf3をサーバーモードで動作させます

```console
# Ubuntu
ubu$ iperf3 -s 
```

Mac側でiPerf3をクライアントモードで立ち上げてUDPのパケットの品質を見てみます。

まずは、tcコマンドでネットワークをクライアントモードで起動します。-uオプションを付けてUDPのパケットロスとJitterを確認します。ここで接続先のホスト名として`ubu`を指定します。ここには、iperf3 severが動作するホストのホスト名またはIPアドレスを指定します。

```console
mac$ iperf3 -c ubu -u
Connecting to host ubu, port 5201
...
[ ID] Interval           Transfer     Bitrate         Jitter    Lost/Total Datagrams
[  7]   0.00-10.00  sec  1.25 MBytes  1.05 Mbits/sec  0.000 ms  0/906 (0%)  sender
[  7]   0.00-10.00  sec  1.25 MBytes  1.04 Mbits/sec  0.437 ms  4/906 (0.44%)  receiver
```

自宅環境では、なにも設定しないときにも0.44%のパケロスと 0.4ms程度のジッターが観測されました。

次にラズパイのコンソールでパケットロスを10%に指定します。

```console
pi$ sudo tc qdisc add dev eth0 root netem
pi$ sudo tc qdisc change dev eth0 root netem loss 10%
```

Macから再度iperf3で測定します。

```console
mac$ iperf3 -c ubu -u
Connecting to host ubu, port 5201
...
[ ID] Interval           Transfer     Bitrate         Jitter    Lost/Total Datagrams
[  7]   0.00-10.00  sec  1.25 MBytes  1.05 Mbits/sec  0.000 ms  0/906 (0%)  sender
[  7]   0.00-10.00  sec  1.12 MBytes   942 Kbits/sec  6.712 ms  93/906 (10%)  receiver
```

パケットロスが約10%になることが確認できました。

続いて、ラズパイのコンソールで遅延を100ms、ジッターを5msに指定します。

```console
pi$ sudo tc qdisc change dev eth0 root netem delay 100ms 5ms
```

Macから再度iperf3で測定します。

```console
mac$ iperf3 -c ubu -u
Connecting to host ubu, port 5201
...
[ ID] Interval           Transfer     Bitrate         Jitter    Lost/Total Datagrams
[  7]   0.00-10.00  sec  1.25 MBytes  1.05 Mbits/sec  0.000 ms  0/906 (0%)  sender
[  7]   0.00-10.00  sec  1.25 MBytes  1.04 Mbits/sec  6.052 ms  93/904 (10%)  receiver
```

6.0msのジッターが観測されました。

往復の遅延時間については、pingコマンドにより確認することができます。

iperf3 に'-R'オプションを付けて起動すると、server --> client方向の確認をすることができます。

## まとめ

Raspberry Piを使って簡易的にネットワークエミュレーション機能付きのWLANブリッジを構築することができました。iperf3を使ってパケットロスとジッターが意図通りに付加されているか検証してみました。