Есть несколько картинок http://vger.kernel.org/~davem/tcp_output.html
Googled с tcp_transmit_skb()
, который является ключевой частью tcp datapath. На его сайте есть еще кое-что интересное http://vger.kernel.org/~davem/
В user - tcp
для передачи части канала данных имеется 1 копия от пользователя в skb с 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 копия от ядра к пользователю skb_copy_datagram_iovec
(вызывается из tcp_recvmsg
). А для tcp_read_sock () может быть копия. Это вызовет sk_read_actor
функцию обратного вызова. Если он соответствует файлу или памяти, он может (или не может) копировать данные из зоны DMA. Если это другая сеть, она имеет skb принятого пакета и может повторно использовать свои данные на месте.
Для udp - получить = 1 копия - skb_copy_datagram_iovec вызывается из udp_recvmsg. передать = 1 копия - udp_sendmsg -> ip_append_data -> getfrag (похоже, ip_generic_getfrag с 1 копией от пользователя, но может быть чем-то вроде sendpage / splice, без копирования страницы.)
Вообще говоря, при отправке из / получения в пространство пользователя должна быть как минимум 1 копия и 0 при использовании нулевой копии (сюрприз!) С исходными / целевыми буферами пространства ядра для данных. Все заголовки добавляются без перемещения пакета, сетевая карта с поддержкой DMA (все современные) будет принимать данные из любого места в адресном пространстве с поддержкой DMA. Для старых карт необходим PIO, поэтому будет еще одна копия, от пространства ядра до регистров / памяти PCI / ISA / smthelse.
UPD: В пути от NIC (но это зависит от ник, я проверил 8139too) к стеку tcp есть еще одна копия : от rx_ring до skb и то же самое для получения: от skb до tx буфер + 1 копия . Вы должны заполнить заголовки ip и tcp, но есть ли в skb их или место для них?