c linux network-programming linux-kernel zero-copy

Copia cero con y sin operaciones Scatter/Gather



linux network-programming (3)

Porque cuando escribe en un socket, los encabezados del paquete se ensamblan en un lugar diferente de sus datos de usuario, por lo que para fusionarse en un paquete de red, el dispositivo necesita capacidad de "recopilación", al menos para obtener los encabezados y datos .

También para evitar que la CPU tenga que leer los datos (y así llenar su caché con cosas inútiles que nunca necesitará), la tarjeta de red también necesita generar sus propias sumas de comprobación de IP y TCP (supongo que TCP está aquí, porque el 99% de sus transferencias masivas de datos van a ser TCP). Esto está bien, porque hoy en día todos pueden.

De lo que no estoy seguro es de cómo todo esto interactúa con TCP_CORK.

La mayoría de los protocolos tienden a tener sus propios encabezados, por lo que un protocolo hipotético se ve así:

Cliente: enviar servidor de solicitud: enviar algunos metadatos; enviar los datos del archivo

Por lo tanto, tendemos a tener una aplicación de servidor ensamblando algunos encabezados en la memoria, emitiendo una escritura (), seguida de una operación similar a sendfile (). Supongo que los encabezados aún se copian en un buffer del kernel en este caso.

Acabo de leer un artículo que explica el mecanismo de copia cero.

Habla de la diferencia entre copia cero con y sin soportes Scatter / Gather.

NIC sin soporte SG , las copias de datos son las siguientes

NIC con soporte SG , las copias de datos son las siguientes

En una palabra, la copia cero con soporte SG puede eliminar una copia de CPU.

Mi pregunta es por qué los datos en el buffer del kernel podrían estar dispersos ?


Re: Mi pregunta es por qué los datos en el buffer del kernel podrían estar dispersos?

Porque ya está disperso. La cola de datos frente a un socket TCP no está dividida en los datagramas que saldrán a la interfaz de red. Scatter le permite mantener los datos donde se encuentran y no tener que copiarlos para crear un búfer plano que sea aceptable para el hardware.

Con la función de recopilación , puede darle a la tarjeta de red un datagrama que se divide en pedazos en diferentes direcciones de la memoria, que pueden ser referencias a los almacenamientos intermedios de socket originales. La tarjeta lo leerá de esas ubicaciones y lo enviará como una sola unidad.

Sin recopilación (el hardware requiere búferes lineales simples), un datagrama debe prepararse como una cadena de bytes asignada contiguamente, y todos los datos que le pertenecen tienen que ser memcpy -d en su lugar desde los búferes que están en cola para su transmisión en el socket .


Debido a que las funciones de mapeo / asignación de memoria del kernel de Linux crearán por defecto regiones de memoria virtualmente contiguas pero posiblemente físicamente disjuntas.
Eso significa la lectura del sistema de archivos que sendfile() internamente va a un búfer en la memoria virtual del kernel , que el código DMA debe "transmutar" (por falta de una palabra mejor) en algo que el motor DMA de la tarjeta de red pueda asimilar.

Como DMA (a menudo pero no siempre) usa direcciones físicas, eso significa que duplicas el búfer de datos (en una región de memoria físicamente contigua especialmente asignada, tu búfer de sockets arriba), o bien lo transfieres one-physical-page-at -a tiempo

Si su motor DMA, por otro lado, es capaz de agregar múltiples regiones de memoria físicamente disjuntas en una única transferencia de datos (que se llama "scatter-gather"), en lugar de copiar el búfer, simplemente puede pasar una lista de direcciones físicas (señalando los subsegmentos físicamente contiguos del buffer del kernel, son sus descriptores agregados ) y ya no necesita iniciar una transferencia DMA por separado para cada página física. Esto generalmente es más rápido, pero si se puede hacer o no depende de las capacidades del motor DMA.