Linuxでcwnd(輻輳ウィンドウサイズ)、rwnd(受信ウィンドウサイズ)の初期値を変更する


概要

『ハイパフォーマンスブラウザネットワーキング』を読んでいて、cwnd(輻輳ウィンドウサイズ)、rwnd(受信ウィンドウサイズ)という単語がでてきた。

気になったので、それぞれについて調べた。Linuxでは初期値(initcwnd, initrwnd)の変更が可能とのことで、その方法を調べ、変更してみた。initrwndについては、それが適用されていることを確認した。initcwndは確認が面倒だったのでやっていない。

環境

  • Ubuntu 17.10

TCPのフロー制御、輻輳制御

cwndとrwndはTCPのフロー制御、輻輳制御と関わる。これについては、『3分間NetWorking』の記事がわかりやすい。

フロー制御
http://www5e.biglobe.ne.jp/~aji/3min/41.html

輻輳制御
http://www5e.biglobe.ne.jp/~aji/3min/42.html

英語だが、この記事も良い。
https://blog.stackpath.com/glossary/cwnd-and-rwnd/

rwndについて

受信ウィンドウサイズ(receive window size)のこと。TCPのフロー制御で用いられる。

TCPでは通信中、お互いの受信ウィンドウサイズを広告しあっている。

cwndについて

輻輳ウィンドウサイズ(congestion window size)のこと。輻輳制御に用いられる。

輻輳ウィンドウサイズとは、データ送信側のウィンドウサイズの制限。通信相手のホストには送られず、送信側ホスト内部で管理される。

実際の通信では、rwndとcwndの小さい方の値が、相手からACKを受け取る前に続けて送信できるデータ量として用いられる。

initrwndとinitcwnd

rwndとcwndの初期値のこと。設定変更が可能なため、変更してみる。

確認、変更

ip routeで確認、変更可能。ip routeでinitrwnd、initcwndが表示されなければ、デフォルトの設定が使われている。

デフォルトの設定については、ipコマンドのmanを見るのがよい。
https://www.systutorials.com/docs/linux/man/8-ip-route/

変更もip routeから行う。

# "..."の部分は、ip routeで出てくる設定をいれればよい
ip route change ... initcwnd 10 initrwnd 10

まとめて設定するなら、このワンライナー。

ip route | while read p; do sudo ip route change $p initcwnd 10 initrwnd 100; done

このサイトから借用した。https://blog.cloudflare.com/optimizing-the-linux-stack-for-mobile-web-per/

initcwndの値は、ssからも確認できる。

$ ss -nli | grep cwnd
     cubic cwnd:10        

パケットキャプチャで確認する(rwnd)

Wiresharkを使用し、initrwndの設定変更による変化をみる。なお、cwndは相手ホストに広告されずパケットからは観察できない。

環境構築と設定

AWSのEC2にApacheをインストールし、通信の相手側のホストにした。クライアントは、手元のPCのWebブラウザ。
EC2のホストにinitrwndを設定する。

$ ip route | while read p; do sudo ip route change $p initrwnd 10; done
$ ip r
default via 172.31.0.1 dev eth0 initrwnd 10
169.254.169.254 dev eth0 scope link initrwnd 10
172.31.0.0/20 dev eth0 proto kernel scope link src 172.31.15.20 initrwnd 10 

ここでは、initrwndとして10を設定している。MSSにこの値を乗算したものがrwndの初期値として使われるようになる。
MSSは、MTUからTCP/IPヘッダ(40byte)をマイナスした値となる。
http://www.infraexpert.com/info/5adsl.htm

MTUはip aifconfigで確認可能で、今回は1500バイトとなっていた。(一般的に1500バイト)
したがってMSSは1460となり、initrwndは14600となる。(はず。)

この状態で、ブラウザからEC2のApacheにアクセスする。

実際に使われたrwndの初期値は、TCPの3ウェイハンドシェイク時の"SYN ACK"で返されるウィンドウサイズで確認が可能。
Wiresharkでは、Window size value(もしくはCalculated window size)の項目を確認する。

結果

initrwndの変更前は、28960だった。そして設定変更を行い実行すると、14480となっていた。
想定は14600のため、12 * 10の差がある。

この原因は、深く調べたわけではないが、TCPのオプションフィールドが影響していると考えられる。TCPのオプションフィールドの分だけ、MSSは小さくなる。
(参考:http://tonetsutomu.com/tone/node/88)

以上により、initrwndの変更が、実際に適用されていることがわかった。

余談

  • initrwndを100に設定しても、実際使われる値は43440となり、意図した結果にならなかった。システムで最大値が設定されていると予想される。
  • initcwndの変更についても、いずれ確認したい