目的
ネットワーク上で制約のある環境を疑似的に再現し、通信の挙動を確認したい。
- 通信帯域の上限を設定する
- 通信の遅延を設定する
やってみた方法
- AmazonLinux2でip forwardを有効にし、ルーターとして利用。
- 通信帯域の上限設定
- iptablesのlimit(hashlimit)
- iprouteのtcコマンド
- 通信の遅延
- iprouteのtcコマンド
ネットワーク構成
EC2(A)---EC2(NAT)(ルーター用)---EC2(B)
- VPCを作成
- サブネットを2つ作成
- EC2(A), EC2(B)をそれぞれのサブネットへ配置
- EC2(NAT)をEC2(A)と同じサブネットで作成。
- EC2(NAT)にENIを追加し、(B)と同じサブネットへ接続
- 各サブネット向けのルートテーブルを作成、相互にルートを追加しておく
- EC2(NAT)のネットワーク設定で「ソース/宛先チェック」を停止しておく
- セキュリティグループは必要なものを空けておく
- EC2(NAT)の基本設定
#IP Forwadingを有効にしておく
sudo sh -c "echo 1 > /proc/sys/net/ipv4/ip_forward"
sudo sh -c "echo net.ipv4.ip_forward=1 >> /etc/sysctl.conf"
#iptablesをインストール・サービスを有効化
sudo yum -y install iptables-services
sudo yum iptables -F
sudo systemctl start iptables
sudo systemctl enable iptables
#tcコマンドを利用するためiproute-tcをインストール
sudo yum -y install iproute-tc
#通信状況を確認するため、dstatをインストール
sudo yum -y install dstat
通信帯域の上限設定1 (最初に検索で見つけた方法)
iptablesのhashlimitを利用。(SCPでの転送確認をやりつつ、EC2(B)にSSHアクセスも行いたかったため、ソースIP単位で制御されるhashlimitを利用。)
limit / limit-burstの考え方の解説は以下参照
https://atmarkit.itmedia.co.jp/ait/articles/1007/14/news102.html
sudo iptables -I FORWARD -p tcp -m tcp --dport <ポート番号> -j REJECT
sudo iptables -I FORWARD -p tcp -m tcp --dport <ポート番号> -m hashlimit --hashlimit-name <設定の名称> --hashlimit <単位あたりのパケット数>/s --hashlimit-burst <バーストするまでの上限> -j ACCEPT
sudo service iptables save
先にREJECTを設定しているのは、hashlimitを超えたときに、この行の条件に合致してREJECTされるようにしているらしい。(本来はDoS攻撃の対策機能の模様。)
(例)
sudo iptables -I FORWARD -p tcp -m tcp --dport 22 -j REJECT
sudo iptables -I FORWARD -p tcp -m tcp --dport 22 -m hashlimit --hashlimit-name sshscplimit --hashlimit 100/s --hashlimit-burst 1 -j ACCEPT
( 100 packet/sec × 1500byte(MTU) = 150,000byte/sec = 約150Kbps )
設定状況確認
$ sudo iptables -L -n
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain FORWARD (policy ACCEPT)
target prot opt source destination
ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:22 limit: up to 100/sec burst 1
REJECT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:22 reject-with icmp-port-unreachable
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
SCPでEC2(A)からEC2(B)へ100MByteのファイルをコピー。EC2(NAT)にて「dstat 1」で帯域を確認。
recvは150kbps前後ですが、sendは60-80kbpsになっていました。受け側での制御なので、こんなものなのでしょうか・・・。
tcによる制御
参考にさせていただいたページ
https://qiita.com/shirok/items/f57e0ecd86abec33a087
https://pig-log.com/tcp-segmentation-offload/
通信帯域の上限設定2
EC2(NAT)のeth1へ設定。(EC2(A)⇒EC2(B)方向へ転送するため、EC2(NAT)の出口側へ設定)
#1Mbpsに上限を設定
#※再起動しても消えないようにするためには、起動スクリプトへの組み込みが必要。
sudo tc qdisc add dev eth1 root tbf limit 1Mb buffer 200Kb rate 1Mbps
sudo ethtool -K eth1 gso off
gso off はセグメンテーションのオフロードをオフにしている。
ネットワークアダプタで処理しないようにするため(・・・と理解している。)
# 設定前のデフォルト状況確認
$ sudo ethtool -k eth1 | grep segmentation-offload
tcp-segmentation-offload: off
generic-segmentation-offload: on
# gsoのみonであったため、offに変更
$ sudo ethtool -K eth1 gso off
# 設定後の状況確認
$ sudo ethtool -k eth1 | grep segmentation-offload
tcp-segmentation-offload: off
generic-segmentation-offload: off
通信の遅延追加
帯域制御と遅延追加は、どうやら排他的になっているようなので、遅延はEC2(NAT)のeth0に設定。
設定の追加
$ sudo tc qdisc add dev eth0 root netem delay <遅延時間>
設定の変更
$ sudo tc qdisc change dev eth0 root netem delay <遅延時間>
設定状況の確認
$ sudo tc qdisc show dev eth0
qdisc netem 8001: root refcnt 3 limit 1000 delay <遅延時間>
(例)
$ sudo tc qdisc add dev eth0 root netem delay 200ms
$ sudo tc qdisc change dev eth0 root netem delay 500ms
$ sudo tc qdisc show dev eth0
qdisc netem 8001: root refcnt 3 limit 1000 delay 500ms