RasPiで作る「不安定なネットワーク」エミュレータの作り方
準備するもの
- Raspberry Pi 4 (USB3.0が欲しいだけ。スペックは要らないからRAM 2GBモデルで十分)
- USB 3.0のGigabit Ethernet アダプタ
- SDカード(多分8GBもあれば十分)
- 設定時用キーボード
- 設定時用モニタ
ネットワークをあれこれいじるので念のためにモニタ・キーボードで設定することにした。
結果から言えばしっかり間違いなく設定できれば大丈夫なので /boot/ssh
を置いてSSH接続で設定してもいいかも。
OSの準備
- Raspberry Pi OS Liteの最新版を適当にSDカードに書き込む
- キーボード・モニタを接続して起動してデフォルトアカウントでログイン
- sudo raspi-configでLocalisation Optionsからキーボードレイアウトを設定する
- ついでにTimeZoneも設定しておく
あとはパスワード変えたり色々設定しておく。
Bridge Networkの準備
(参考:http://nort-wmli.blogspot.com/2019/09/rapberry-pi-bridge-utils.html)
まずは sudo apt update
して sudo apt install bridge-utils
としてbrctlとかを入れる。
/etc/network/interfaces
auto br0
iface br0 inet manual
bridge_ports eth0 eth1
bridge_stp off
bridge_maxwait 3
/etc/dhcpcd.conf
denyinterfaces eth0 eth1
interface br0
static ip_address=192.168.2.3/24
static routers=192.168.2.1
static domain_name_servers=192.168.2.1 8.8.8.8
固定IP関係はそれぞれの環境に応じて設定。
再起動してbr0に指定したIPアドレスが割り振られていて、eth0/eth1に割り振られていなければOK。
tc & tcguiのインストール
設定しやすいようにtcguiを入れてみる。
sudo apt install iproute2 python3-flask git
git clone https://github.com/tum-lkn/tcgui.git
-
sudo python3 main.py --ip 0.0.0.0 --port 80
で試しに起動 - 別マシンからブラウザでアクセスして試してみる
自動起動設定
/etc/rc.localの exit 0
の前に以下を挿入する(最後の&まで忘れずに)
nohup python3 /home/pi/tcgui/main.py --ip 0.0.0.0 --port 80 --regex 'eth[01]' &
ネットワークデバイスのうち、eth0とeth1で設定すればいいっぽい。
eth0をいじるとuplinikが、eth1をいじるとdownlinkがロスしたり遅延したりする・・・らしい(この記事に書いてある)。ラズパイから出ていくパケットにだけ効果があるということかな?
Read only file system 設定
sudo raspi-config
して Performance Options
の Overlay File System
を有効にしておく。これで電源ぶちっと抜いてオフにしたときの耐性が高くなる。
以下、iperf3とpingを使って調べていくので、外側にサーバ、内側にクライアントを置いておく。構成は大体こんな感じ。今回サーバは適当なLinuxマシン、クライアントはMacBook Proを使用した(MacBook ProはWiFiを切ってUSB LANアダプタで有線接続)。双方にiperf3を入れておく。
下側のネットワークは普通にハブ使ってもよし、直結でも良し。
tcguiの画面はこんな感じ。
まずは正常時の確認。
% iperf3 -c 192.168.2.193
Connecting to host 192.168.2.193, port 5201
[ 5] local 192.168.2.110 port 52807 connected to 192.168.2.193 port 5201
[ ID] Interval Transfer Bitrate
[ 5] 0.00-1.00 sec 97.9 MBytes 822 Mbits/sec
[ 5] 1.00-2.00 sec 107 MBytes 900 Mbits/sec
[ 5] 2.00-3.00 sec 109 MBytes 913 Mbits/sec
[ 5] 3.00-4.00 sec 110 MBytes 921 Mbits/sec
[ 5] 4.00-5.00 sec 111 MBytes 928 Mbits/sec
[ 5] 5.00-6.00 sec 108 MBytes 906 Mbits/sec
[ 5] 6.00-7.00 sec 108 MBytes 905 Mbits/sec
[ 5] 7.00-8.00 sec 108 MBytes 910 Mbits/sec
[ 5] 8.00-9.00 sec 108 MBytes 904 Mbits/sec
[ 5] 9.00-10.00 sec 109 MBytes 918 Mbits/sec
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval Transfer Bitrate
[ 5] 0.00-10.00 sec 1.05 GBytes 903 Mbits/sec sender
[ 5] 0.00-10.00 sec 1.05 GBytes 901 Mbits/sec receiver
iperf Done.
% ping -c 100 -i 0.2 192.168.2.193
PING 192.168.2.193 (192.168.2.193): 56 data bytes
64 bytes from 192.168.2.193: icmp_seq=0 ttl=64 time=0.952 ms
64 bytes from 192.168.2.193: icmp_seq=1 ttl=64 time=1.395 ms
64 bytes from 192.168.2.193: icmp_seq=2 ttl=64 time=1.137 ms
64 bytes from 192.168.2.193: icmp_seq=3 ttl=64 time=1.176 ms
64 bytes from 192.168.2.193: icmp_seq=4 ttl=64 time=1.291 ms
64 bytes from 192.168.2.193: icmp_seq=5 ttl=64 time=0.972 ms
〜〜〜略〜〜〜
64 bytes from 192.168.2.193: icmp_seq=96 ttl=64 time=1.323 ms
64 bytes from 192.168.2.193: icmp_seq=97 ttl=64 time=1.078 ms
64 bytes from 192.168.2.193: icmp_seq=98 ttl=64 time=1.218 ms
64 bytes from 192.168.2.193: icmp_seq=99 ttl=64 time=1.106 ms
--- 192.168.2.193 ping statistics ---
100 packets transmitted, 100 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 0.917/1.223/1.539/0.128 ms
900Mbpsでpingは1ms程度、この程度ではパケロスはほぼ出ない普通なネットワークになっている。
まずは帯域制限をしてみる。Rate
のところに値を入れれば良い。ちなみにソースを読んでコメントで分かったのだが「bit」はbit per second、「bps」はbyte per secondらしい。
とりあえず500Mbpsにしてみると・・・
Rateしか入れてないのになぜかDelayとLimitがついてるのが気になる・・・あとで確認しよう。
% iperf3 -c 192.168.2.193
Connecting to host 192.168.2.193, port 5201
[ 5] local 192.168.2.110 port 52909 connected to 192.168.2.193 port 5201
[ ID] Interval Transfer Bitrate
[ 5] 0.00-1.00 sec 35.3 MBytes 296 Mbits/sec
[ 5] 1.00-2.00 sec 57.3 MBytes 480 Mbits/sec
[ 5] 2.00-3.00 sec 57.3 MBytes 481 Mbits/sec
[ 5] 3.00-4.00 sec 57.1 MBytes 479 Mbits/sec
[ 5] 4.00-5.00 sec 57.2 MBytes 480 Mbits/sec
[ 5] 5.00-6.00 sec 57.2 MBytes 480 Mbits/sec
[ 5] 6.00-7.00 sec 57.2 MBytes 480 Mbits/sec
[ 5] 7.00-8.00 sec 57.2 MBytes 479 Mbits/sec
[ 5] 8.00-9.00 sec 57.1 MBytes 479 Mbits/sec
[ 5] 9.00-10.00 sec 57.1 MBytes 479 Mbits/sec
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval Transfer Bitrate
[ 5] 0.00-10.00 sec 550 MBytes 461 Mbits/sec sender
[ 5] 0.00-10.00 sec 549 MBytes 460 Mbits/sec receiver
iperf Done.
ちょっと低く出てるのが気になるが制限されていることがわかる。
特にコマンドラインオプションを与えていない場合はクライアント→サーバ方向の通信を測定しているらしい。
なので、eth0の設定を外し、eth1で帯域制限をしてみると・・・
% iperf3 -c 192.168.2.193
Connecting to host 192.168.2.193, port 5201
[ 5] local 192.168.2.110 port 52925 connected to 192.168.2.193 port 5201
[ ID] Interval Transfer Bitrate
[ 5] 0.00-1.00 sec 53.5 MBytes 449 Mbits/sec
[ 5] 1.00-2.00 sec 92.4 MBytes 775 Mbits/sec
[ 5] 2.00-3.00 sec 92.8 MBytes 779 Mbits/sec
[ 5] 3.00-4.00 sec 93.3 MBytes 783 Mbits/sec
[ 5] 4.00-5.00 sec 91.8 MBytes 770 Mbits/sec
[ 5] 5.00-6.00 sec 95.3 MBytes 799 Mbits/sec
[ 5] 6.00-7.00 sec 92.0 MBytes 772 Mbits/sec
[ 5] 7.00-8.00 sec 91.0 MBytes 763 Mbits/sec
[ 5] 8.00-9.00 sec 90.6 MBytes 760 Mbits/sec
[ 5] 9.00-10.00 sec 91.7 MBytes 769 Mbits/sec
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval Transfer Bitrate
[ 5] 0.00-10.00 sec 884 MBytes 742 Mbits/sec sender
[ 5] 0.00-10.00 sec 883 MBytes 741 Mbits/sec receiver
iperf Done.
帯域制限が外れていることが確認できる。iperfには -R
オプションがあり、これを設定すると計測に使う通信がサーバ→クライアントになる。
% iperf3 -c 192.168.2.193 -R
Connecting to host 192.168.2.193, port 5201
Reverse mode, remote host 192.168.2.193 is sending
[ 5] local 192.168.2.110 port 52927 connected to 192.168.2.193 port 5201
[ ID] Interval Transfer Bitrate
[ 5] 0.00-1.00 sec 33.0 MBytes 277 Mbits/sec
[ 5] 1.00-2.00 sec 34.2 MBytes 287 Mbits/sec
[ 5] 2.00-3.00 sec 34.2 MBytes 287 Mbits/sec
[ 5] 3.00-4.00 sec 34.2 MBytes 287 Mbits/sec
[ 5] 4.00-5.00 sec 34.2 MBytes 287 Mbits/sec
[ 5] 5.00-6.00 sec 34.2 MBytes 287 Mbits/sec
[ 5] 6.00-7.00 sec 34.2 MBytes 287 Mbits/sec
[ 5] 7.00-8.00 sec 34.2 MBytes 287 Mbits/sec
[ 5] 8.00-9.00 sec 34.2 MBytes 287 Mbits/sec
[ 5] 9.00-10.00 sec 34.2 MBytes 287 Mbits/sec
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval Transfer Bitrate Retr
[ 5] 0.00-10.00 sec 342 MBytes 287 Mbits/sec 0 sender
[ 5] 0.00-10.00 sec 341 MBytes 286 Mbits/sec receiver
iperf Done.
eth0のDelayを200msに設定してみる。相変わらず表示がおかしいけど設定はされている様子。
iperf3ではDelayは測ってくれないのでpingで見る。
% ping 192.168.2.193 -c 10 -i 0.2
PING 192.168.2.193 (192.168.2.193): 56 data bytes
Request timeout for icmp_seq 0
64 bytes from 192.168.2.193: icmp_seq=0 ttl=64 time=201.231 ms
64 bytes from 192.168.2.193: icmp_seq=1 ttl=64 time=201.311 ms
64 bytes from 192.168.2.193: icmp_seq=2 ttl=64 time=201.285 ms
64 bytes from 192.168.2.193: icmp_seq=3 ttl=64 time=201.131 ms
64 bytes from 192.168.2.193: icmp_seq=4 ttl=64 time=201.233 ms
64 bytes from 192.168.2.193: icmp_seq=5 ttl=64 time=201.291 ms
64 bytes from 192.168.2.193: icmp_seq=6 ttl=64 time=201.263 ms
64 bytes from 192.168.2.193: icmp_seq=7 ttl=64 time=201.277 ms
64 bytes from 192.168.2.193: icmp_seq=8 ttl=64 time=201.098 ms
64 bytes from 192.168.2.193: icmp_seq=9 ttl=64 time=201.269 ms
--- 192.168.2.193 ping statistics ---
10 packets transmitted, 10 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 201.098/201.239/201.311/0.067 ms
こんな感じに均一に200ms程度の遅延が追加されている。右側のボックスはDelayに揺らぎを持たせる設定で、左に200、右に50と入れると
% ping 192.168.2.193 -c 10 -i 0.2
PING 192.168.2.193 (192.168.2.193): 56 data bytes
Request timeout for icmp_seq 0
64 bytes from 192.168.2.193: icmp_seq=0 ttl=64 time=243.310 ms
64 bytes from 192.168.2.193: icmp_seq=1 ttl=64 time=167.944 ms
64 bytes from 192.168.2.193: icmp_seq=2 ttl=64 time=190.028 ms
64 bytes from 192.168.2.193: icmp_seq=3 ttl=64 time=230.964 ms
64 bytes from 192.168.2.193: icmp_seq=4 ttl=64 time=178.245 ms
64 bytes from 192.168.2.193: icmp_seq=5 ttl=64 time=209.384 ms
64 bytes from 192.168.2.193: icmp_seq=6 ttl=64 time=208.928 ms
64 bytes from 192.168.2.193: icmp_seq=7 ttl=64 time=241.856 ms
64 bytes from 192.168.2.193: icmp_seq=8 ttl=64 time=166.389 ms
64 bytes from 192.168.2.193: icmp_seq=9 ttl=64 time=154.431 ms
--- 192.168.2.193 ping statistics ---
10 packets transmitted, 10 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 154.431/199.148/243.310/30.909 ms
こんな風になる。
eth0に30%のパケロスを設定するとこんな感じ
% ping 192.168.2.193 -c 10 -i 0.2
PING 192.168.2.193 (192.168.2.193): 56 data bytes
Request timeout for icmp_seq 0
64 bytes from 192.168.2.193: icmp_seq=0 ttl=64 time=243.310 ms
64 bytes from 192.168.2.193: icmp_seq=1 ttl=64 time=167.944 ms
64 bytes from 192.168.2.193: icmp_seq=2 ttl=64 time=190.028 ms
64 bytes from 192.168.2.193: icmp_seq=3 ttl=64 time=230.964 ms
64 bytes from 192.168.2.193: icmp_seq=4 ttl=64 time=178.245 ms
64 bytes from 192.168.2.193: icmp_seq=5 ttl=64 time=209.384 ms
64 bytes from 192.168.2.193: icmp_seq=6 ttl=64 time=208.928 ms
64 bytes from 192.168.2.193: icmp_seq=7 ttl=64 time=241.856 ms
64 bytes from 192.168.2.193: icmp_seq=8 ttl=64 time=166.389 ms
64 bytes from 192.168.2.193: icmp_seq=9 ttl=64 time=154.431 ms
--- 192.168.2.193 ping statistics ---
10 packets transmitted, 10 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 154.431/199.148/243.310/30.909 ms
kounoikeyuusuke@MacBook-Pro ~ % ping 192.168.2.193 -c 100 -i 0.2
PING 192.168.2.193 (192.168.2.193): 56 data bytes
64 bytes from 192.168.2.193: icmp_seq=0 ttl=64 time=1.046 ms
64 bytes from 192.168.2.193: icmp_seq=1 ttl=64 time=1.234 ms
Request timeout for icmp_seq 2
64 bytes from 192.168.2.193: icmp_seq=3 ttl=64 time=1.101 ms
64 bytes from 192.168.2.193: icmp_seq=4 ttl=64 time=0.979 ms
Request timeout for icmp_seq 5
64 bytes from 192.168.2.193: icmp_seq=6 ttl=64 time=1.129 ms
Request timeout for icmp_seq 7
64 bytes from 192.168.2.193: icmp_seq=8 ttl=64 time=1.215 ms
64 bytes from 192.168.2.193: icmp_seq=9 ttl=64 time=1.128 ms
64 bytes from 192.168.2.193: icmp_seq=10 ttl=64 time=1.212 ms
〜〜〜略〜〜〜
64 bytes from 192.168.2.193: icmp_seq=93 ttl=64 time=1.057 ms
64 bytes from 192.168.2.193: icmp_seq=94 ttl=64 time=1.278 ms
64 bytes from 192.168.2.193: icmp_seq=95 ttl=64 time=1.297 ms
64 bytes from 192.168.2.193: icmp_seq=96 ttl=64 time=1.233 ms
64 bytes from 192.168.2.193: icmp_seq=97 ttl=64 time=0.976 ms
64 bytes from 192.168.2.193: icmp_seq=98 ttl=64 time=1.249 ms
64 bytes from 192.168.2.193: icmp_seq=99 ttl=64 time=0.980 ms
--- 192.168.2.193 ping statistics ---
100 packets transmitted, 71 packets received, 29.0% packet loss
round-trip min/avg/max/stddev = 0.771/1.107/1.297/0.122 ms
iperf3でも-uオプションをつけてUDP通信させるとわかりやすい。
% iperf3 -c 192.168.2.193 -u
Connecting to host 192.168.2.193, port 5201
[ 5] local 192.168.2.110 port 54707 connected to 192.168.2.193 port 5201
[ ID] Interval Transfer Bitrate Total Datagrams
[ 5] 0.00-1.00 sec 129 KBytes 1.05 Mbits/sec 91
[ 5] 1.00-2.00 sec 127 KBytes 1.04 Mbits/sec 90
[ 5] 2.00-3.00 sec 129 KBytes 1.05 Mbits/sec 91
[ 5] 3.00-4.00 sec 129 KBytes 1.05 Mbits/sec 91
[ 5] 4.00-5.00 sec 127 KBytes 1.04 Mbits/sec 90
[ 5] 5.00-6.00 sec 129 KBytes 1.05 Mbits/sec 91
[ 5] 6.00-7.00 sec 127 KBytes 1.04 Mbits/sec 90
[ 5] 7.00-8.00 sec 129 KBytes 1.05 Mbits/sec 91
[ 5] 8.00-9.00 sec 127 KBytes 1.04 Mbits/sec 90
[ 5] 9.00-10.00 sec 129 KBytes 1.05 Mbits/sec 91
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval Transfer Bitrate Jitter Lost/Total Datagrams
[ 5] 0.00-10.00 sec 1.25 MBytes 1.05 Mbits/sec 0.000 ms 0/906 (0%) sender
[ 5] 0.00-10.00 sec 884 KBytes 724 Kbits/sec 0.031 ms 281/906 (31%) receiver
receiver側がパケットロスしているので、サーバ側から見た結果を報告しているのかな?
左側だけを使うと均一な確率でパケットロスする。右側の入力を使うと「一度発生するとその後も連続して発生しやすい」ような状況を作ることが出来る。詳しくはこのへん参照。
Duplicateでパケットが重複するようにも出来る。30% Duplicateするようにしてこんな感じ。
% ping 192.168.2.193 -c 100 -i 0.2
PING 192.168.2.193 (192.168.2.193): 56 data bytes
64 bytes from 192.168.2.193: icmp_seq=0 ttl=64 time=1.018 ms
64 bytes from 192.168.2.193: icmp_seq=0 ttl=64 time=1.033 ms (DUP!)
64 bytes from 192.168.2.193: icmp_seq=1 ttl=64 time=1.241 ms
64 bytes from 192.168.2.193: icmp_seq=2 ttl=64 time=0.935 ms
64 bytes from 192.168.2.193: icmp_seq=3 ttl=64 time=1.278 ms
64 bytes from 192.168.2.193: icmp_seq=3 ttl=64 time=1.301 ms (DUP!)
64 bytes from 192.168.2.193: icmp_seq=4 ttl=64 time=1.268 ms
64 bytes from 192.168.2.193: icmp_seq=4 ttl=64 time=1.292 ms (DUP!)
64 bytes from 192.168.2.193: icmp_seq=5 ttl=64 time=1.150 ms
64 bytes from 192.168.2.193: icmp_seq=5 ttl=64 time=1.174 ms (DUP!)
64 bytes from 192.168.2.193: icmp_seq=6 ttl=64 time=1.102 ms
64 bytes from 192.168.2.193: icmp_seq=7 ttl=64 time=1.033 ms
64 bytes from 192.168.2.193: icmp_seq=8 ttl=64 time=1.243 ms
64 bytes from 192.168.2.193: icmp_seq=9 ttl=64 time=1.261 ms
64 bytes from 192.168.2.193: icmp_seq=10 ttl=64 time=0.939 ms
64 bytes from 192.168.2.193: icmp_seq=10 ttl=64 time=0.962 ms (DUP!)
〜〜〜略〜〜〜
64 bytes from 192.168.2.193: icmp_seq=94 ttl=64 time=0.815 ms
64 bytes from 192.168.2.193: icmp_seq=95 ttl=64 time=1.255 ms
64 bytes from 192.168.2.193: icmp_seq=96 ttl=64 time=1.312 ms
64 bytes from 192.168.2.193: icmp_seq=96 ttl=64 time=1.336 ms (DUP!)
64 bytes from 192.168.2.193: icmp_seq=97 ttl=64 time=1.095 ms
64 bytes from 192.168.2.193: icmp_seq=98 ttl=64 time=1.128 ms
64 bytes from 192.168.2.193: icmp_seq=99 ttl=64 time=1.298 ms
--- 192.168.2.193 ping statistics ---
100 packets transmitted, 100 packets received, +32 duplicates, 0.0% packet loss
round-trip min/avg/max/stddev = 0.707/1.129/1.390/0.156 ms
残りの設定項目は説明だけで。Reorderは一定確率でパケットの順序が入れ替わる。Corruptは一定確率でパケットの中身が壊れる(ビットが反転する)。Limitは・・・ちょっと良く分かってないので後で調べる。
とりあえず有線で欲しかったものは出来た。ただ、せっかくのRasPi4なんだしhostapdを使ってWiFiにも同じ機能を作っても良いかもしれない。WiFi対応すればスマホクライアントにも同じことが出来るようになるはず。
tcguiで247.9sって出るのが気持ち悪くてUbuntu 20.04 64bitで設定してみた。
ブリッジの作成
以下を/etc/netplan/99-cloud-init.yamlに記載
network:
version: 2
ethernets:
eth0:
dhcp4: false
dhcp6: false
eth1:
dhcp4: false
dhcp6: false
bridges:
br0:
interfaces: [eth0, eth1]
dhcp4: true
dhcp6: true
optional: true
なんとなくDHCPにしたのでIPアドレスは起動時に見るか、avahi入れて名前でアクセスするかのどっちかにしないとならない。固定IPにするならこの辺を参考にして設定する。
自動起動の設定
/etc/systemd/system/tcgui.serviceに下記を記載
[Unit]
Description=TC Web GUI
After=network.target
[Service]
WorkingDirectory=/home/ubuntu/tcgui
ExecStart=/usr/bin/python3 main.py --ip 0.0.0.0 --port 80 --regext eth[01]
[Install]
WantedBy=multi-user.target
systemctl enable tcgui
で有効化する。
Read Only File Systemの設定
後で調べる