GSO/GROを調査中、TCPのAckとの関係がよく分からなくなってきて混乱したため、ChatGPTとやりとりした内容をまとめたものです。
ChatGPTに出力させた記事ですが、内容は面白いと思ったことと、将来また自分が同じような疑問を持ちそうだと思ったため自分用の記事として公開します。
自分が混乱した点として、GROで複数パケットを1つのデータにまとめてしまうと(一つのSKBにまとめてしまうと)、正しくTCPのAckを返せなくなるのでは?と思ったことでした。TCPのAckは送信したパケットごとにAckを返す必要はなく、複数のパケットが届いた時にそれが連続していればここまで届いたというのを知らせるため最後のパケットに対するAckを返せばよいだけです。ですのでGRO/GSOとも共存できるということですね。
参考: GRO/GSOについてのLinuxのドキュメント
Segmentation Offloads — The Linux Kernel documentation
― ACK の意味論から理解する Linux のオフロード設計 ―
Linux のネットワークチューニングを調べていると、必ず出てくるのが GRO や GSO です。
一見すると「パケットをまとめる」「分割をオフロードする」という単純な最適化に見えますが、
その設計は TCP の ACK の意味論と完全に噛み合うように作られています。
この記事では、
- TCP の ACK は何を保証しているのか
- GRO / GSO は TCP のどこを変えて、どこを変えていないのか
- なぜ GRO / GSO が TCP の設計と相性が良いのか
を整理します。
TCP の ACK は「パケット確認」ではない
TCP の ACK は次の意味を持ちます。
このシーケンス番号未満のデータは、すべて順序通りに受信した
ACK は「パケットごとの確認」ではなく、
ストリームとしてどこまで連続して届いたかを示します。
パケットが欠けたときの ACK
送信側が次の 3 セグメントを送ったとします。
packet 1: seq=1000, len=1000 packet 2: seq=2000, len=1000 packet 3: seq=3000, len=1000
受信側が packet 1 と packet 3 を受信し、packet 2 が欠けた場合、
返される ACK は次の通りです。
ACK = 2000
後ろのデータを受信していても、
欠けている部分がある限り ACK は進みません。
GRO(Generic Receive Offload)とは何か
GRO は 受信側の最適化です。
- 同一フロー
- シーケンス番号が連続
- ヘッダが互換
という条件を満たす TCP セグメントを、
TCP スタック内部でまとめて 1 つの skb として扱います。
GRO は TCP の何を変えるのか
GRO が変えるのは 処理単位だけです。
- ワイヤ上の TCP セグメントは変わらない
- シーケンス番号空間も変わらない
- ACK の意味論も変わらない
TCP の正しさを壊すことはありません。
GRO skb の中身
GRO 後の skb は、
- 先頭に Ethernet / IP / TCP ヘッダ
- payload は複数 TCP セグメント分
を保持します。
ただし 1 つの巨大な連続バッファではなく、
scatter-gather 的に複数のメモリ断片を束ねた構造です。
GRO と ACK の関係
TCP の ACK は累積 ACK です。
複数の TCP セグメントをまとめて受信できた場合でも、
ACK = 最後まで受信したシーケンス番号
を 1 回返せば十分です。
GRO は TCP の性質を前提にした最適化です。
GSO(Generic Segmentation Offload)とは何か
GSO は 送信側の最適化です。
アプリケーションや TCP スタックは大きなデータ塊を扱い、
MTU 単位への分割はカーネル後段や NIC(TSO)に任せます。
GSO が成立する理由
送信側が論理的に 1 回送ったデータは、
- どこで分割されても
- 何個の TCP セグメントになっても
受信側から見れば連続した TCP ストリームです。
ACK もストリームの連続性に基づいて返されます。
GRO / GSO が壊さないもの
GRO / GSO は次のものを変更しません。
- TCP の状態機械
- 再送制御
- congestion control
- ACK の意味論
やっているのは
処理をまとめて CPU 負荷を下げることだけです。
なぜ TCP と GRO / GSO は相性が良いのか
TCP はもともと
- ストリーム指向
- 累積 ACK
という性質を持っています。
GRO / GSO はその設計を活かし、
- skb 数削減
- 割り込み削減
- 高スループット化
を実現しています。
まとめ
- TCP の ACK はストリームの確認
- GRO は受信側で処理単位をまとめる
- GSO は送信側で分割を遅延させる
- TCP の意味論は一切変わらない
- だから安全に高速化できる