http://vger.kernel.org/~davem/tcp_output.html
Google で検索するとtcp_transmit_skb()
、tcp データパスの重要な部分である画像がいくつかあります。彼のサイトhttp://vger.kernel.org/~davem/にはもっと興味深いものがあります
user - tcp
datapath の送信部分には、user から skb への1 つのコピーskb_copy_to_page
( による送信時tcp_sendmsg()
) と0 のコピーdo_tcp_sendpages
( による呼び出し) がありtcp_sendpage()
ます。未配信セグメントの場合に備えて、データのバックアップを保持するためにコピーが必要です。カーネル内の skb バッファーは複製できますが、それらのデータは最初の (元の) skb に残ります。Sendpage は、他のカーネル部分からページを取得し、バックアップ用に保持できます (COW のようなものがあると思います)。
パスを呼び出します (lxr から手動で)。送信tcp_push_one
/__tcp_push_pending_frames
tcp_sendmsg() <- sock_sendmsg <- sock_readv_writev <- sock_writev <- do_readv_writev
tcp_sendpage() <- file_send_actor <- do_sendfile
受け取るtcp_recv_skb()
tcp_recvmsg() <- sock_recvmsg <- sock_readv_writev <- sock_readv <- do_readv_writev
tcp_read_sock() <- ... spliceread for new kernels.. smth sendfile for older
受信では、カーネルからユーザー(から呼び出される) への1 つのコピーが存在する可能性があります。そして tcp_read_sock() にはコピーがあります。コールバック関数を呼び出します。ファイルまたはメモリに対応する場合、DMA ゾーンからデータをコピーする場合とコピーしない場合があります。他のネットワークの場合、受信パケットの skb があり、そのデータをその場で再利用できます。skb_copy_datagram_iovec
tcp_recvmsg
sk_read_actor
udp の場合 - 受信 = 1 コピー -- udp_recvmsg から呼び出された skb_copy_datagram_iovec。送信 = 1 コピー-- udp_sendmsg -> ip_append_data -> getfrag (ユーザーからの 1 コピーの ip_generic_getfrag のようですが、ページ コピーのない sendpage/splice のようなものかもしれません。)
一般的に言えば、ユーザー空間との間で送受信する場合は少なくとも 1 つのコピーが必要であり、データのカーネル空間ソース/ターゲット バッファーでゼロコピー (驚き!) を使用する場合は 0 コピーが必要です。パケットを移動せずにすべてのヘッダーが追加され、DMA 対応の (すべて最新の) ネットワーク カードは、DMA 対応のアドレス空間の任意の場所からデータを取得します。古いカードの場合、PIO が必要なので、カーネル空間から PCI/ISA/smthese I/O レジスタ/メモリまで、もう 1 つのコピーがあります。
UPD: NIC (ただし、これは nic に依存しますが、8139too をチェックしました) から tcp スタックへのパスには、もう 1 つのコピーがあります: rx_ring から skb へ、受信の場合も同じです: skb から tx buffer +1copy へ。ip および tcp ヘッダーを入力する必要がありますが、skb にはそれらが含まれているか、または配置されていますか?