TCP Basics
TCP 基本機能
- 高信頼転送 (Sequence Number)
- 喪失パケットの再送
- 誤り検出 (Checksum)
- フロー制御 (Window Scalig)
- 輻輳制御
高信頼転送 (Sequence Number)
シーケンス番号の基本動作
TCP は「シーケンス番号」を使ってデータの各バイトを識別する。
3 の最初の 2 ステップで、双方のホストは初期シーケンス番号 (ISN) をやりとりする。
この番号は任意であり、 TCP シーケンス番号予測攻撃への防御のために予測不可能な値とすべきである。
3 way handshake

毎度 ack のある通信

Window サイズのある通信
第41回レイヤ4 TCP ウィンドウ | 3 分間 Networking
http://www5e.biglobe.ne.jp/aji/3min/41.html
累積確認応答 (Cumulative Acknowledgment)
受信側が確認応答を返すとき、そのセグメントで示されている確認応答番号は、対応するシーケンス番号未満のデータを全て受信済みであることを示す。
選択確認応答 (Selective Acknowledgment)
RFC 2018 で「選択確認応答 (SACK)」というものが追加された。
累積確認応答とは異なり、受信側が不連続なブロックを正しく受信したという確認応答を返せるようにしたもの。
SACK オプションは必須ではなく、両者がサポートしている場合だけ使われる。これはコネクション確立時に調整される。
SACK オプションは主な TCP スタックでサポートされており、広く使われている。
SACK Header
RFC 2018 - TCP Selective Acknowledgment Options
https://tools.ietf.org/html/rfc2018
ヘッダフォーマットは以下の通り。

Sack-Permitted Option で、 SACK を使うことを伝える。これは、 3 way handshake の SYN で送られる。
また、 Left Edge of Block と Right Edge of Block で挟まれた区間のシーケンス番号を持つセグメントは受け取りを完了しましたよ、ということを伝える。
喪失パケットの再送
再送制御
RFC 6298 Computing TCP's Retransmission Timer
https://tools.ietf.org/html/rfc6298
RTT : round-trip time
SRTT : smoothed RTT
SRTT = (1 - alpha) * SRTT + alpha * R'
RTTVAR : mean deviation (平均偏差) of RTT
RTTVAR = (1 - beta) * RTTVAR + beta * |SRTT - R'|
RTO : retransmission timeout
RTO = SRTT + max 4 * RTTVAR
で、実際はどうなってるの?って話。
実装
どうしてもカーネルバージョン依存になる。
LinuxのTCP SYNの再送間隔の初期値が3秒から1秒に変更されていた
https://www.na3.jp/entry/20131129/p1
執筆時点で一番新しい Amazon Linux 2 AMI 2.0.20190313 x86_64 HVM gp2 にて確認。
# cat /proc/version
Linux version 4.14.104-95.84.amzn2.x86_64 (mockbuild@ip-10-0-1-219) (gcc version 7.3.1 20180303 (Red Hat 7.3.1-5) (GCC)) #1 SMP Sat Mar 2 00:40:20 UTC 2019
kernel ソースはとりあえずここから引っ張ってくる。
https://elixir.bootlin.com/linux/v4.14/source/include/net/tcp.h
https://elixir.bootlin.com/linux/v4.14/source/net/ipv4
initial RTO
RFC 6298
(2.1) Until a round-trip time (RTT) measurement has been made for a
segment sent between the sender and receiver, the sender SHOULD
set RTO <- 1 second, though the "backing off" on repeated
retransmission discussed in (5.5) still applies.
include/net/tcp.h L143
#define TCP_TIMEOUT_INIT ((unsigned)(1*HZ)) /* RFC6298 2.1 initial RTO value */
ちゃんと RFC通りになってる。
set RTO
TCP再送タイムアウト時間の規格と実装
http://co1row.hatenablog.com/entry/2017/09/26/012335
ほぼ上に書いてくれてる。あとでまとめる…。
how many retries are done when active opening a connection
SYN 試行時のリトライ回数は 6 回。
include/net/tcp.h L107
#define TCP_SYN_RETRIES 6 /* This is how many retries are done
* when active opening a connection.
* RFC1122 says the minimum retry MUST
* be at least 180secs. Nevertheless
* this value is corresponding to
* 63secs of retransmission with the
* current initial RTO.
*/
これは ALAMI 2 でももちろんデフォルト値一緒。
# cat /proc/sys/net/ipv4/tcp_syn_retries
6
誤り検出 (Checksum)
チェックサム・フィールドは、ヘッダおよびテキストの全 16 ビットワードの 1 の補数の総和の 1 の補数の下位 16 ビットである。
オクテット数が奇数の場合、最後のオクテットの右にゼロの列をパディングして 16 ビットワードにしてからチェックサムを計算する。
このパディングはセグメントの一部として送信することはない。チェックサム計算時、チェックサム・フィールド自体はゼロとして計算する。
チェックサム計算時には、 IPv4 パケットヘッダを含めたような、擬似ヘッダも含めて行う。

チェックサムの計算
流れとしては以下の通りとなる。
- オクテット数が偶数になるようにパディング (ゼロ埋め)
- 全 16 ビットワードを「 1 の補数表現」で加算
- 総和をビット毎に反転
- 下位 16 ビットをチェックサムフィールドに格納
パケットから組み上げ
Checksum の手計算 にてまとめた。
こちらを参考にしてください。
フロー制御 (Window Scalig)
MTU / MSS
MTU
MTU (Maximum Transmission Unit)とは、ノードが隣接したネットワークへ、 1 回の通信で転送可能な最大のデータグラムサイズのこと。
つまり、 NW 機器や端末のインターフェース において、中身をカプセル化できる最大サイズ。
Ethernet では 1500 Bytes であり、 PPPoE では 1492 Bytes となる。
MSS
MTU から TCP ヘッダと IP パケットを除いたもの。
MTU が 1500 すると、 20 Bytes ずつの IP, TCP ヘッダを除き、 1460 Bytes が MSS となる。
Adjusting MSS
例えば、経路の途中で MSS が変更される場合がある。
他のカプセル化ヘッダなどを受け付けることができる。
パケットを例に
SYN パケットの TCP Option MSS では 1460 Bytes を指定。
SYN+ACK パケットの MSS は 1420 Bytes となっている。これは、サーバ側がそれを指定してきて送ってきたから。
このとき、小さいほうの値が利用されるべきである (SHOULD) 。
クライアントはこれを尊重し、多分 1420 Bytes を使う。
もし指定がなければ、デフォルトの 536 を利用する。
https://tools.ietf.org/html/rfc879
THE TCP MAXIMUM SEGMENT SIZE IS THE IP MAXIMUM DATAGRAM SIZE MINUS
FORTY.The default IP Maximum Datagram Size is 576.
The default TCP Maximum Segment Size is 536.
Window Size
Window Size value is the sender indicating how much TCP receiver it has allocated.
最大 2 Bytes なので、 65535 まで指定できる。
カーネルパラメータで調整可能。
Window Scale
65535 よりもっと受信したい場合は、 Window Scale Option を利用。 SYN に入る。
シフトカウントで数えられ、左へ何ビットシフトするか、という考え。
最大 14 bit シフトできる。
Calculated Window Size
Window Scale が 2 だったら、 2 bit シフトで、 Window Size を 4 倍にする。
Window Scale が 7 だったら、 7 bit シフトで、 Window Size を 128 倍にする。
Window Scaling
処理しきれなくなると、サイズを小さくしていく。
受信しきれなくなると Window Size を 0 にして、サーバ側に「もう受け取れない」ということを通知する。
サーバ側とのコネクションは維持され、 Window が open になるまで待つ。
バッファが空いて受信可能になると open にする。
Window size scaling factor
Window size scaling factor は、ハンドシェイク時に示された Window Scale Value のこと。
Window Scale オプションはハンドシェイク時にしか利用できない。
コラム: PPP / PPPoE
PPP
電話回線を使ってデータをやり取りするために使われていたプロトコル。
PPP はさまざまなプロトコルを 1 つの回線を使って転送できるように考慮されており、 ISDN や電話回線、専用線といったさまざまな通信回線で利用されている。
LAN 上ではイーサネットを使うので MAC アドレスから相手先を認識できたが、 WAN だと公衆電話網を使っていたのでイーサネットが使えなかった。
The Point-to-Point Protocol (PPP)
https://tools.ietf.org/html/rfc1661
PPPoE
イーサネットは公衆電話網を使えないので、 PPP でカプセル化する必要がある。
PPP では電話番号で通信先を識別して、一対一の通信で PPP サーバーに接続し、インターネットに接続していたのに対し、 PPPoE では多対多のネットワークであるイーサネット上で、 PPPoE サーバーと MAC アドレスによって仮想回線を確立する。
確立した後は PPP 同様、ユーザー認証をしてインターネットにつなぐことができる。
輻輳制御
ネットワークが対応可能な量を超えるパケットをノードが送信したときに、ルーターバッファーオーバーフローの形式で輻輳が発生する。
それらを緩和するための仕組みが輻輳制御。
主に以下の 3 方式が存在。
- Loss ベース
(New)Reno, H-TCP, BIC, CUBIC など - Delay ベース
Vegas, Westwood, Fast TCP - ハイブリッド
Illinois, DCTCP, CTCP, YeAH
関連用語
RWND
Receiver Window Size のこと。
TCP コネクションにおいて、実際に相手に通知を行う Window Size を表す。
つまり、送信先(受信者)の制限値。
CWND
Congestion Window Size のこと。
送信者がどのくらいまでデータを送れるかを表す Window Size のことで、相手に通知はされない。
輻輳制御では、送信側が CWND により制限をかけてネットワークの輻輳を避ける。
What is CWND and RWND?
https://blog.stackpath.com/glossary/cwnd-and-rwnd/
Increasing the TCP initial congestion window
https://lwn.net/Articles/427104/
RFC 3390 : Increasing TCP's Initial Window
https://tools.ietf.org/html/rfc3390
Loss ベース
パケットロスを観測し、ロスが増えれば輻輳が発生したと見なして送信量を抑える方式。
Reno/NewReno
http://www.net.c.dendai.ac.jp/~yutaro/#2-3
CUBIC
もとの論文
CUBIC: A New TCP-Friendly High-Speed TCP Variant
https://www.cs.princeton.edu/courses/archive/fall16/cos561/papers/Cubic08.pdf
RFC
CUBIC for Fast Long-Distance Networks
https://tools.ietf.org/html/rfc8312
その他解説記事
新しいTCPフロー制御アルゴリズムBBR | ブログ
https://okuranagaimo.blogspot.com/2017/06/bbr.html
"CUBIC: A new TCP-friendly high-speed TCP variant"を読んだ | ゆううきブログ
https://blog.yuuk.io/entry/cubictcp
複数の CUBIC TCP コネクションにおける RTT 公平性の改善
https://ipsj.ixsq.nii.ac.jp/ej/?action=repository_action_common_download&item_id=105096&item_no=1&attribute_id=1&file_no=1
Delay ベース
パケットのRTTを観測し、送信量を制御する方式。
RTT の計測値と推測値を用いて、計測値が推測値を下回れば空いているとみなしウィンドウサイズを大きくし、計測値が推測値を上回れば混雑してきたとみなし、輻輳ウィンドウサイズを小さくするといった流れ。
Vegas
http://www.net.c.dendai.ac.jp/~yutaro/#2-5
ハイブリッド
その名の通り、 Loss ベースと Delay ベースを組み合わせた方式。
参考資料
TCP congestion control
https://en.wikipedia.org/wiki/TCP_congestion_control
TCP各バージョンの輻輳制御の比較
http://www.net.c.dendai.ac.jp/~yutaro/#2-1
JANOG41 TCP輻輳制御技術動向
https://www.janog.gr.jp/meeting/janog41/application/files/4615/1727/7615/janog41-sp09tcp-ishizaki-02.pdf
RFCs
- RFC 973 : 基本スペック
- RFC 2581 : 輻輳制御アルゴリズム
