EN JA
ZERO_COPY(9)
ZERO_COPY(9) FreeBSD Kernel Developer's Manual ZERO_COPY(9)

名称

zero_copy, zero_copy_sockets0 コピーソケットコード

書式

options SOCKET_SEND_COW
options SOCKET_RECV_PFLIP

解説

FreeBSD カーネルは、ソケットの読み込みと書き込みでデータコピーを無視する機能を含んでいます。

このコードは、通常のネットワーク I/O の間にデータが CPU によって全くコピーされないので、まとめて 0 コピーソケットコードとして知られています、どちらかといえば、それは、ユーザのバッファから (送信のために) NIC まで DMA されるか、または、 NIC から (受信のために) ユーザに与えられているバッファまで DMA されます。

0 コピーソケットコードは、標準のソケット読み込み書き込み動作を使用しますが、そのため、プログラマがこの機能をうまく利用するように試みるとき、承知しているべきであるいくつかの制限と制約があります。

送信データのためには、送信している NIC が持たなければならない、特別の必要条件や能力はありません。しかしソケットに書き込まれたデータは、少なくとも 1 ページのサイズでカーネルにマップされるために整列されたページでなければなりません。ページサイズと整列制約が満たされないなら、それは、通常のソケット I/O の場合のように、カーネルにコピーされます。

ユーザは、データがカーネルによって解放される前にソケットに書き込まれるバッファを上書きしないように、そしてコピーオンライト (copy-on-write) マッピングはクリアするように、慎重であるべきです。バッファが、カーネルによって断念される前に上書きされるなら、データはコピーされ、CPU 利用とメモリ帯域幅利用における節約は実現されていません。

socket(2) API は本当に、いつ彼のデータが実際に回線上に送信されたか、または、いつカーネルバッファからデータを解放したかのどんな指示もユーザに与えません。 TCP のようなプロトコルにおいて、データは、それが反対側によって承認されるまで、カーネルのそばに保持されます。再転送が要求される場合に承認が受信されない場合、保持されなければなりません。

アプリケーションの観点から、データを回線上に送出して、 (TCP ベースのソケットのために) カーネルで解放したことを保証する最も良い方法は、アプリケーションアプリケーションとネットワーク環境にふさわしいソケットバッファサイズ ( setsockopt(2) マニュアルページの SO_SNDBUF ソケットオプションを参照) を設定することです、そして、利用者は、バッファを再利用する前にソケットバッファサイズとして 2 倍多く送出したことを確実にします。 TCP のためには、送信と受信ソケットバッファサイズは一般的に、直接 TCP ウィンドウサイズに対応しています。

受信データで、0 コピー受信コードをうまく利用するためには、ユーザはアーキテクチャのページサイズより大きい MTU に設定される NIC がなければなければなりません。 (例えば、i386 のためには、4KB でしょう。) 加えて、動作する 0 コピー受信のためには、パケットペイロードは少なくとも 1 ページの大きさでページ整列されていなければなりません。訳注: ペイロードはヘッダ部を除いたデータの本体。

整列されたページのペイロードを実現するためには、着信パケットを複数のバッファに分割することができる NIC を必要とします。また、一般的に、ペイロードがそれ自体のバッファで始動することを確実にするためには、ある種のインテリジェント NIC を必要とします。これは“header splitting” (ヘッダ分割) と呼ばれます。現在、ヘッダ分割をサポートする唯一の NIC は、わずかに変更されたファームウェアを走らせるボードに基づいている Alteon Tigon 2 です。 FreeBSD ti(4) ドライバは、Tigon 2 ボードのみのための変更されたファームウェアを含んでいます。しかしながら、複数のバッファに受信されたパケットを入れるのを許して、ヘッダを 1 つのバッファに入れ、ペイロードを別のものに入れるべきであるかを決定することができるくらいのプログラマビリティがある NIC のために、ヘッダ分離コードを書くことができます。

また、利用者は、使用している NIC がせめてパケットを複数のバッファに分離する能力があるなら、 NIC の変更を必要としないヘッダ分離を形成することができます。これは、利用者の大部分の共通のパケットヘッダサイズのために NIC ドライバを最適化することを必要とします。そのサイズ (イーサネット + IP + TCP ヘッダ) が一般的に 66 バイトであるなら、例えば、利用者は、特定のパケットが 66 バイト長となるように最初のバッファを設定するでしょう、そして、その後のバッファは 1 ページの大きさとなるでしょう。正確に 66 バイト長であるヘッダを持っているパケットに関しては、利用者のペイロードは整列されたページとなります。

0 コピー受信が動作するの他の要件は、ソケットから読み込まれたデータのための宛先であるバッファが少なくとも 1 ページの大きさであり、整列されたページでなければなりません。

受信側の 0 コピーのための明らかな要件は、何らかのヘッダ分離を行うために十分プログラマブルである NIC ハードウェアなしで対処することは不可能です。ほとんどの NIC がそれほどプログラマブルでないか、またはそれらのメーカがそれらのファームウェアとソースコードを共有していないので、 0 コピーが受信のためのこのアプローチは、広く役に立ちません。

カーネルの中からデータをコピーすることに関連している CPU オーバヘッドを軽減することを潜在的に助けるかもしれない、RDMA や TCP Offload のような他のアプローチがあります。ほとんどの知られている技術は、動作するためのある種の NIC レベルのサポートを必要とします、そして、そのような技術についての説明することは、このマニュアルページの範囲を超えています。

0 コピー送信と 0 コピー受信コードは、それぞれ kern.ipc.zero_copy.sendkern.ipc.zero_copy.receive sysctl 変数を通して個々にオフにすることができます。

関連項目

sendfile(2), socket(2), ti(4)

歴史

0 コピーソケットコードは、 FreeBSD 5.0 ではじめて登場しましたが、少なくとも 1999 年中頃以来、それはパッチ形式で存在していました。

作者

0 コピーソケットコードは、元々 Andrew Gallatin <gallatin@FreeBSD.org>によって書かれ、実質的に Kenneth Merry <ken@FreeBSD.org>によって変更されて更新されました。

バグ

送信メカニズムに基づいた COW は、安全でなく、カーネルのクラッシュの結果となるかもしれません。
October 23, 2012 FreeBSD