クイックノート

ちょっとした発見・アイデアから知識の発掘を

テスト用に回線速度をあえて下げる方法

Webページは様々な通信環境で見られるので、
回線速度が遅いとどう見えるのかをテストしてみたいと思うことがあります。

linux では、「tc」コマンドを使って帯域制限をかけることができるのですが、
基本的には、外に向かって出ていく通信に対しての制限が前提となっていて、
内側に入ってくる通信に対して制限をかけるには、少々面倒な操作が必要になります。

ということで、内向きの回線速度を下げる方法についてまとめておきます。

tc コマンド

今回は linux で標準で利用できる「tc」コマンドを使って回線速度を操作します。

「tc」コマンドは、「traffic control」の略で、
PC 上で行う通信に対して様々な操作をかけることができます。

f:id:u874072e:20180822124633p:plain

通信に対する操作は「qdisc」と呼ばれる機能で実現され、
上の図のように、OSのカーネルとドライバの中間に配置されます。

この qdisc パケットを転送するスピードをわざと落とすことができるのですが、
基本的には、外向きに送信されるパケットについて操作を行うことが前提となっています。

このままだと、回線の弱いクライアントが、
あるWebサーバーに接続した時にどのように振る舞うのかを調べようと思った時に、
データを送信するWebサーバー側で制限しないといけません。
この場合、どちらかと言うと、
データを受け取るクライアント側で帯域を制限した方が、
実際のシチュエーションにも合っていますし、
サーバーではなく、テスト用のクライアントをいじる方が安心です。

それでは、内向きのパケットを操作するにはどうすればいいでしょうか。

パケットを疑似的なデバイスにリダイレクトする

外向きにしか帯域制限がかけられないなら、
内向きの通信をなんとか、外向きに変えることを考えましょう。

実は、内向きのパケットを疑似的なデバイスにリダイレクトすることで、
これが出来てしまいます。

f:id:u874072e:20180822144336p:plain

ここでは、ifb と呼ばれる疑似デバイスを使います。
上の図では、通常の通信を行っている「eth0」などのNICから入ってきた通信を、
qdisc上で、疑似デバイス「ifb0」を経由するように
リダイレクトしている様子を表しています。

eth0 からは、内向きの通信として、qdiscに入ってきた通信が、
ifb0にリダイレクトされるときは、外向きの通信としてqdiscを出ていき、
また、内向きに戻ってきています。

このifb0に向かってパケットを送り出す時に、
qdisc で帯域制限をかければ、内向きの通信にも帯域制限をかけることができます。

内向きの帯域制限のコマンド

見通しがたったところで、
上の方法を実現するコマンドを入力していきます。

準備

まずは、必要となるカーネルモジュールをロードしておきます。
ここでは、疑似デバイスを利用するための「ifb」と、
パケットのリダイレクトを行うための「act_mirred」をロードします。

   modprobe ifb
   modprobe act_mirred

疑似デバイスの生成

パケットを経由させるための疑似デバイスを生成します。

   ip link set dev ifb0 up

これで、「ifb0」という名前の疑似デバイスが生成されました。
「ifconfig」で確認することができます。

リダイレクトの設定

それでは、生成した疑似デバイスに向けてリダイレクトを設定します。

   tc qdisc add dev [デバイス名] ingress handle ffff:
   tc filter add dev [デバイス名] parent ffff: protocol ip u32 match u32 0 0 flowid 1:1 action mirred egress redirect dev ifb0

※[デバイス名] には、通信に用いるデバイス名が入ります。通常は「eth0」等です。

1行目は、内向きに対して、qdisc を生成しています。
2行目でその qdisk で行うリダイレクトの処理を記述しています。

具体的には、全てのパケットにマッチするフィルターを設定して、
フィルターのアクションとして、疑似デバイス「ifb0」へのリダイレクトを設定しています。

疑似デバイス上での帯域制限

最後に、疑似デバイス「ifb0」の外向きの通信に対して帯域制限を設定します。

   tc qdisc add dev ifb0 root handle 1: htb default 10
   tc class add dev ifb0 parent 1:1 classid 1:10 htb rate [制限帯域]bit

※ [制限帯域]には設定する帯域の数値が入ります。10m, 1g 等の表記が使えます。

1行目では、帯域制限用のqdisc「htb」をifb0に対して設定しています。
2行目で、帯域の数値を設定しています。

これで、内向きの通信が疑似デバイスを経由して、
疑似デバイスに転送されるときに帯域の制限を受けることで、
内向きの通信速度を意図的に落とすことができるようになりました。

スループット計測例

上の方法で実際に内向きの回線速度が制限されていることを確かめるために、
Web上での回線速度測定ツールを使って、回線速度を計ってみました。

fast.com

まずは、帯域制限前の速度です。

f:id:u874072e:20180822152712p:plain:w400

続いて、10Mbpsに制限した際の
帯域制限後の速度です。

f:id:u874072e:20180822152951p:plain:w400

ちゃんと回線速度を落とすことができていますね!

途中で帯域の値を変更したい場合

テスト中に、途中で回線速度をさらに落としたり、増加させたりすることもあります。
その場合は、次のコマンドで設定の変更が可能です。

   tc class change dev ifb0 parent 1:1 classid 1:10 htb rate [制限帯域]bit

帯域の設定のコマンドを「add」から「change」に変えただけです。
これで、既に設定された帯域に上書きで新しい帯域制限が設定されます。

設定の解除方法

最後に、テストが終わって設定を解除する際には、
次のコマンドを実行します。

   tc qdisc del dev $DEVICE ingress handle ffff:
   tc qdisc del dev ifb0 root handle 1: htb

これで、qdisc に加えたリダイレクトと帯域制限が解除されます。

プライバシーポリシー