# iip: an integratable TCP/IP stack
> [!abstract] 概要
> 本稿は、開発者や研究者がプロジェクトへ高性能な TCP/IP スタックを組み込みやすくすることを目指す、統合可能な TCP/IP スタック iip を提示する。
> 新たに iip を開発した動機は、既存の性能最適化 TCP/IP スタックが大きな統合複雑性を招く一方、既存の移植性を重視した TCP/IP スタックは大きな性能制約を持つことである。
> 本稿では、TCP/IP スタック実装と開発者が提供するコードとの責任境界を見直し、許容できない統合複雑性を導入せずに統合容易性と高性能を両立する API を導入する。
> さらに、iip の性能測定値と、設計が考慮した性能上重要な要因が性能へ与える影響を報告する。
## 論文情報
- 著者: [[Kenichi Yasukata]]
- 所属: [[IIJ Research Laboratory]]
- 媒体: *ACM SIGCOMM Computer Communication Review*, Volume 54, Issue 1
- 発表日: 2024-01-30
- DOI: https://doi.org/10.1145/3687230.3687233
- 実装: [[iip]]、リポジトリ: https://github.com/yasukata/iip
- 入力 PDF: 冒頭に Joseph Camp による公開レビュー 1 ページを含み、本論文本文は印字ページ 22〜28 に収録されている。
## 概要
TCP/IP スタックには、性能最適化を優先して外部コンポーネントへ強く依存するものと、移植性を優先して高性能 NIC の機能を十分に使えないものがある。
iip は、TCP/IP 処理そのものを提供し、プラットフォーム依存の機能を開発者実装のコールバックへ委ねる API を採用することで、統合時の衝突を避けながら NIC オフロード、ゼロコピー I/O、マルチコア処理を利用する。
(Source: [[.raw/papers/iip_Integratable_TCPIP_Stack.txt]] §1–§3)
## 問題設定
高性能 TCP/IP スタックは CPU アーキテクチャ、NIC、OS、ライブラリ、コンパイラへ依存しやすい。
特定のアプリケーションフレームワークや OS のスレッド実行環境に組み込まれたスタックを別のシステムへ移すと、既存のスレッド実行環境との機能衝突が起こる。
また、split、merge、unified という CPU コア割り当てモデルのうち、実装側が一つだけを想定していると、統合先のワークロードに適したモデルを選べない。
移植性を重視するスタックにも、NIC のチェックサム・オフロード、TSO、scatter-gather、RSS、LRO を十分に利用できない問題がある。
内部バッファと NIC バッファの間でコピーが必要になるとゼロコピー I/O を実現しにくく、複数コア間の共有データ構造やロックも小メッセージ処理の拡張性を制限する。
(Source: [[.raw/papers/iip_Integratable_TCPIP_Stack.txt]] §2)
## 提案手法
### 外部依存の間接化
iip は TCP/IP 処理コードから CPU アーキテクチャ、NIC、OS、ライブラリ、コンパイラ固有の機能を直接参照しない。
C89 で実装し、C++98 系のシステムへ組み込めるようにする。
標準 C ライブラリや POSIX API にも直接依存せず、プラットフォーム依存機能へのアクセスを API のコールバックとして開発者に実装させる。
iip は TCP/IP 処理だけを担当するため、特定の外部コンポーネントとの機能衝突を避けやすい。
一方、iip を利用する開発者のコードが別の TCP/IP スタックへ統合される場合には、iip 自体が衝突点になる。
論文は、ネットワーク機能へのアクセスを開発者側の抽象化層で包み、必要に応じて別の TCP/IP スタックへ置換できるようにすることを推奨する。
(Source: [[.raw/papers/iip_Integratable_TCPIP_Stack.txt]] §3.1.1–§3.1.2)
### CPU コア割り当てと状態管理
iip は TCP/IP 処理を実行するループを実装せず、開発者が用意した任意のスレッドから呼び出す関数だけを提供する。
これにより、ネットワーク処理とアプリケーション処理を同一スレッドで実行する unified モデル、別スレッド・同一コアで実行する merge モデル、別コアで実行する split モデルを統合側が選択できる。
TCP/IP 処理コードをステートレスにし、プロトコル処理の状態を context object に保持する。
開発者がスレッドごとに専用の context object を渡すことで、実行中の共有メモリアクセス競合を避ける。
その代わり、同一 TCP 接続のパケットを同じスレッドへ振り分ける必要があり、論文は NIC の RSS をその例として挙げる。
(Source: [[.raw/papers/iip_Integratable_TCPIP_Stack.txt]] §3.1.3, §3.1.6)
### API の責任境界
iip の API は、開発者が実装するコールバックと iip が提供する関数からなる。
共通引数には TCP/IP 処理状態を保持する context object、開発者側のパケット表現を包む packet object、任意の開発者固有データを渡す opaque object がある。
開発者が実装する主なコールバックは次のとおりである。
- 汎用メモリアロケータ: 動的メモリの確保と解放
- NIC 制御: パケット送信と NIC オフロード機能へのアクセス
- パケット管理: パケット表現とバッファの確保、解放、操作
- 汎用ユーティリティ: 現在時刻などのプラットフォーム依存処理
- 入力イベント処理: TCP 接続受付や TCP ペイロード受信時のアプリケーション処理
iip が提供する主な関数は、周期イベントの呼び出し、受信パケットの投入、ARP・ICMP・TCP・UDP の送信、TCP 接続の確立と切断である。
パケット管理側が参照カウントを維持すれば、複数のパケット表現から同じバッファを参照できる。
(Source: [[.raw/papers/iip_Integratable_TCPIP_Stack.txt]] §3.2)
### NIC オフロードとゼロコピー I/O
iip は、利用可能な場合にチェックサム、scatter-gather、TSO、LRO といった NIC 機能を使う。
ゼロコピー送信では、開発者側のペイロードへ隣接する領域にヘッダーを書き込まず、独立したバッファへヘッダーを作り、scatter-gather によってヘッダーとペイロードを非連続なメモリから送信する。
これにより、複数の送信先へ同じペイロードを送るときのヘッダー領域の競合を避ける。
(Source: [[.raw/papers/iip_Integratable_TCPIP_Stack.txt]] §3.1.4–§3.1.5, §3.2.3)
## 実験設定
2 台のマシンを直接接続して評価した。
各マシンは 16 コアの Intel Xeon Gold 6326 を 2 基、128 GB DRAM、Mellanox ConnectX-5 100 Gbps NIC を備え、Linux 6.2 を実行する。
パケット I/O には DPDK を使う。
NIC オフロードとゼロコピー I/O を有効にし、unified モデルを採用した構成を default とする。
評価は、1 バイトの TCP ペイロードを交換する TCP ping-pong、CPU コア割り当てモデルの比較、TCP バルクデータ転送の三つで構成する。
小メッセージ交換では ponger 側の割り当てコア数を変え、バルク転送では送信側または受信側の NIC オフロードを個別に無効化した。
(Source: [[.raw/papers/iip_Integratable_TCPIP_Stack.txt]] §4)
## 実験結果
### 小メッセージ交換
TCP ping-pong では、ponger 側を 1 コアから 32 コアへ増やすと、default 構成のスループットは 2.9 million requests/sec から 72.3 million requests/sec へ増加した。
scatter-gather を無効にすると小さなパケットでは default よりわずかに高いスループットになる場合があり、NIC の scatter-gather 利用に伴うソフトウェア・オーバーヘッドがメモリコピーを上回る可能性を示す。
チェックサム・オフロードを無効にすると、default に対して 11〜26% のスループット低下が観測された。
**図1: TCP ping-pong による小メッセージ処理性能**
![[_attachments/iip_Integratable_TCPIP_Stack/fig01-tcp-ping-pong.png]]
(図1。1 バイト payload の TCP ping-pong を対象に、(a) CPU コア数に対するスループット、(b) 32 コア時の 99 パーセンタイルレイテンシーとスループット、(c) CPU コア割り当てモデル別の 99 パーセンタイルレイテンシーとスループットを示す。Source: [[.raw/papers/iip_Integratable_TCPIP_Stack.pdf]], Figure 1.)
### CPU コア割り当てモデル
split モデルは負荷が小さいとき、merge モデルより低いレイテンシーを示す。
一方、負荷が高くなると merge モデルは、ネットワーク処理とアプリケーション処理の間で未使用 CPU サイクルを融通できるため、split より高いスループットを示す。
unified モデルはスレッド間通信と CPU 資源境界の両方を避けるため、評価した三モデルの中で最も高い性能を示した。
(Source: [[.raw/papers/iip_Integratable_TCPIP_Stack.txt]] §4.2, Figure 1c)
### バルクデータ転送
default 構成は NIC の帯域上限に近いスループットへ到達した。
送信側で scatter-gather を無効にした場合の低下はデータサイズが大きいほど顕著になり、ゼロコピー送信が CPU キャッシュ消費の抑制に寄与することを示す。
送信側で TSO を無効にするとスループットはほぼ半分になり、さらに送信側のチェックサム・オフロードも無効にすると default の約 10% まで低下した。
このワークロードでは受信側の LRO 無効化による低下は見られなかったが、受信側のチェックサム・オフロードを無効にするとスループットは約 10% まで低下した。
**図2: TCP バルクデータ転送スループット**
![[_attachments/iip_Integratable_TCPIP_Stack/fig02-tcp-bulk-throughput.png]]
(図2。データサイズを変化させ、default と送受信側の scatter-gather、TSO、LRO、チェックサム・オフロード無効化を比較する。Source: [[.raw/papers/iip_Integratable_TCPIP_Stack.pdf]], Figure 2.)
## 考察
iip の中心的な設計判断は、TCP/IP スタックがすべての実行環境を内包するのではなく、プラットフォーム依存の責任を API とコールバックの境界へ移すことである。
この境界により、同じ TCP/IP 処理コードを異なるメモリアロケータ、NIC、スレッド実行環境、パケット表現へ接続できる。
さらに、context object に状態を集約し、処理ループを利用側へ開放することで、統合先が CPU コア割り当てとパケット振り分けの方針を選択できる。
この設計は、8 ビット・16 ビット機器で状態とバッファを削減した [[@2003__MobiSys__Full TCP IP for 8-Bit Architectures|uIP]]、ユーザー空間でコアローカル処理を行う [[@2014__NSDI__mTCP - a Highly Scalable User-level TCP Stack for Multicore Systems|mTCP]]、NIC 側へ TCP 状態処理を移す [[@2020__NSDI__AccelTCP - Accelerating Network Applications with Stateful TCP Offloading|AccelTCP]] と異なる層の責任境界を選ぶ。
iip はスタックを小型化するのではなく、統合先が性能に必要な機構を選べるようにすることで、統合容易性と性能の両立を試みる。
## 強み / 弱点・課題
### 強み
- TCP/IP 処理を C89 準拠で実装し、libc、POSIX、特定 OS、特定 NIC への直接依存を避けた点
- コールバック、context object、packet object、opaque object を組み合わせ、外部依存と責任境界を明示した点
- split、merge、unified の CPU コア割り当てモデルを利用側のループへ委ね、RSS と組み合わせたマルチコア処理を実現した点
- scatter-gather、TSO、LRO、チェックサム・オフロードとゼロコピー I/O を API 設計の段階から扱った点
### 弱点・課題
- POSIX socket など主要 OS のネットワーク API に準拠せず、既存プログラムとの直接互換性を持たない
- コールバック実装、NIC からのパケット投入、周期呼び出し、入力イベント処理を統合側が実装する必要があり、統合オーバーヘッドが残る
- 新規実装であるため、成熟した既存 TCP/IP スタックより実装の成熟度が低い
- 本稿の評価は 2 台の Linux 6.2 マシン、ConnectX-5、DPDK、TCP ping-pong とバルク転送に限られ、他の NIC、OS、ワークロードへの一般化は確認されていない
- 小メッセージでは scatter-gather を無効にした方がわずかに速い場合があり、ゼロコピーは常に有利とは限らない
## 出典
- [[.raw/papers/iip_Integratable_TCPIP_Stack.pdf]]
- [[.raw/papers/iip_Integratable_TCPIP_Stack.txt]]
- [iip: An Integratable TCP/IP Stack](https://ccronline.sigcomm.org/2024/iip-an-integratable-tcp-ip-stack/)
- [yasukata/iip](https://github.com/yasukata/iip)