QUIC para el kernel de Linux
(lwn.net)- Se envió el primer parche para integrar oficialmente el protocolo QUIC en el kernel de Linux
- El objetivo es mejorar las limitaciones de TCP (latencia, head-of-line blocking, osificación del protocolo por dispositivos intermedios, etc.)
- QUIC se basa en UDP, ofrece soporte de multistream y cifrado de extremo a extremo, y su adopción en el kernel podría ampliar las posibilidades de uso en más plataformas y hardware
- Aunque el rendimiento de la implementación inicial en el kernel se midió por debajo de TCP y de kernel TLS, se espera que mejore con offloading de hardware y optimizaciones futuras
- Actualmente hay un intenso debate sobre su soporte en Samba, SMB/NFS basado en kernel, curl y otros, aunque todavía se prevé que falte tiempo para su integración en mainline
Contexto de la aparición de QUIC y limitaciones de TCP
- QUIC fue creado con el objetivo de resolver varios problemas que TCP presenta en Internet
- La experiencia web se degrada por la latencia causada por el 3-way handshake del proceso de conexión de TCP, la falta de soporte sólido para multistream y el fenómeno de head-of-line blocking ante pérdida de paquetes
- Los metadatos de TCP se transmiten sin cifrar, lo que implica riesgo de filtración de información, y las middleboxes (dispositivos intermedios) filtran el tráfico según la información de la conexión, lo que termina derivando en osificación del protocolo (ossification)
- Incluso los intentos de mejorar TCP, como Multipath TCP, no pueden funcionar con normalidad si no se hacen pasar por TCP tradicional
Características de QUIC y ventajas técnicas
- QUIC funciona sobre UDP y puede establecer conexiones rápidamente sin un 3-way handshake separado durante el proceso de conexión
- Su diseño de transmisión multistream evita que la pérdida de paquetes afecte a todo el flujo
- Los datos de transporte relacionados con QUIC siempre van con cifrado de extremo a extremo (basado en TLS), por lo que los dispositivos intermedios no pueden acceder a los mensajes internos
- Si el entorno de red permite el paso de paquetes UDP, QUIC también puede funcionar con normalidad
Resumen del parche de integración de QUIC en el kernel de Linux
- El parche presentado introduce un nuevo tipo de protocolo llamado IPPROTO_QUIC, lo que permite aprovechar la llamada al sistema socket() existente
- Igual que con TCP, se pueden usar llamadas como bind(), connect(), listen() y accept(), aunque el procesamiento posterior tiene diferencias
- La gestión de sesiones TLS y el proceso de autenticación/cifrado se manejan en espacio de usuario, y tras establecer la conexión cada extremo debe completar el TLS handshake antes de poder enviar y recibir datos
- Después de la conexión inicial, los resultados de la negociación TLS pueden almacenarse en caché, lo que permite acelerar considerablemente la reconexión entre dos sistemas
Retos de rendimiento y perspectivas
- La implementación de QUIC dentro del kernel presentada todavía muestra desventaja en rendimiento frente a kernel TLS y TCP
- Menos de un tercio del throughput frente a TLS en kernel, y hasta 4 veces menos throughput que TCP incluso con el cifrado desactivado
- Entre las causas señaladas están la falta de soporte para segmentation offloading, copias adicionales de datos en la ruta de envío y el proceso de cifrado de encabezados
- Se espera que el rendimiento mejore cuando se agregue soporte para offloading de hardware y se optimice la implementación dentro del kernel
Estado de adopción y perspectivas futuras
- En varios proyectos como el servidor/cliente de Samba, los sistemas de archivos SMB y NFS del kernel, y curl, hay un debate activo sobre el soporte de QUIC dentro del kernel
- El parche tiene unas 9,000 líneas y por ahora solo incluye código de soporte de bajo nivel. La implementación completa está prevista en parches adicionales
- La revisión del código y el debate sobre su integración apenas están comenzando, por lo que todavía se espera que falte tiempo para su uso real
- Considerando el precedente reciente del protocolo Homa, cuya integración al kernel requirió 11 envíos durante 9 meses, se estima que QUIC también podría entrar en mainline después de 2026
1 comentarios
Comentarios de Hacker News
ssl_preread_server_nameen la configuración de NGINX para hacerproxy_passde las solicitudes de ciertos dominios a otra instancia de NGINXLa primera instancia simplemente reenvía el flujo TLS en bruto (incluyendo
proxy_protocol), y la segunda instancia se encarga de la terminación TLS realEste método es efectivo al implementar failover: si la ruta principal del servidor se cae, actualizas el registro DNS A para que apunte al NGINX de la máquina de failover, y esa instancia enruta las solicitudes de dominios específicos de vuelta al backend original por una ruta separada
Es conveniente porque no hace falta duplicar toda la configuración TLS
Pero este método no aplica a HTTP/3
HTTP/3 está basado en QUIC, funciona sobre UDP, y cifra el SNI durante el handshake, así que no se puede hacer enrutamiento por dominio con
ssl_preread_server_nameMe pregunto si existe alguna alternativa que permita enrutamiento basado en SNI en HTTP/3, o si, cuando se necesita esta función, todavía hay que quedarse con HTTP/1.1 o HTTP/2 sobre TLS
En la práctica, el comportamiento varía según la implementación del cliente (ver el estado del soporte de registros HTTPS en Chromium en este enlace del issue), pero cuando falla una conexión QUIC, el cliente suele hacer fallback de forma transparente a HTTP/1.1/2, y también respeta el encabezado Alt-Svc
Si el failover es planeado, también podrías simplemente dejar de enviar el encabezado Alt-Svc y esperar a que expire por timeout hacia la instancia alternativa
Si realmente necesitas routing de QUIC, por suerte la información de SNI siempre está en el primer paquete, así que se puede enrutar inspeccionando paquetes
El udpgrm de Cloudflare puede servir como referencia, y esto funciona mientras no haya ECH (Encrypted Client Hello)
Si hay ECH, el router tendría que tener la clave de descifrado para poder tomar decisiones de routing, y a nivel de protocolo también se podría diseñar failover en cascada
Puedes ver una implementación concreta en este ejemplo de udpgrm
Si un atacante logra acceder a ese servidor, también le sería fácil emitir de nuevo el certificado SSL, así que en vez de complicarte con un sistema de failover sofisticado, probablemente tenga más sentido terminar TLS directamente
Personalmente nunca he logrado reproducir por mí mismo las ventajas de rendimiento o confiabilidad de QUIC
Lo he probado repetidamente durante años, pero casi siempre termino desactivándolo por temas de rendimiento u otros motivos
El failover basado en DNS también tarda varios minutos en reflejarse en la práctica, y con clientes simples como los navegadores muchas veces ni siquiera funciona bien
Por eso uso directamente un manejador
onerrorpara cargar una segunda rutaPor ejemplo, para tracking publicitario uso código de ese estilo, y también ofrezco un wrapper del API de fetch de la misma forma
Este enfoque ha sido mucho más eficiente que cualquier otro intento
Aunque el navegador falle al establecer una conexión QUIC (incluso si está anunciada en DNS), hará fallback automáticamente a HTTP/1 o HTTP/2 sobre TLS, así que puedes usar exactamente el mismo método de failover que ya tenías
Una característica de diseño de HTTP/3 es precisamente no exponer información del endpoint hasta la capa TLS
Personalmente lo veo como una ventaja
HAProxy puede hacer proxy de TLS en bruto, pero no routing por nombre de host
Cloudflare Tunnel tiene una función especial que permite routing por nombre de host sin terminar TLS, pero para usarla también necesitas llevar tu DNS a Cloudflare
Me recordó a esta tira de xkcd
Me pregunto si la misma limitación también existe en entornos TCP+TLS cuando se usa Encrypted Client Hello
Imagino que la respuesta sería casi la misma
Siento que esta discusión va en la dirección de ir resolviendo esos problemas poco a poco
También queda abierta la posibilidad de soporte por hardware en las tarjetas de red en el futuro
Pero hoy la mayor parte del tráfico de internet va entre móviles y servidores, y ahí es donde QUIC y HTTP/3 realmente brillan
Para otros usos se puede seguir usando TCP
Supongo que se verá como varias conexiones, pero con caching interno
A mí me gustaría más recibir explícitamente un objeto de conexión y abrir streams aparte, aunque por ahora también podría aceptar el enfoque actual
Revisando esta discusión relacionada, parece que, si esto no es una extensión, en el lado del servidor también se pueden crear nuevos streams después de establecer la conexión
Del lado del cliente, aunque en realidad sean streams, parece difícil abstraerlos como “conexiones” separadas, y en el fondo da la impresión de que hace falta una abstracción de API completamente nueva
Probablemente cada nuevo stream termine entregando un file descriptor vía
recvmsgQuisiera algo tan resistente a problemas de red como Mosh, pero conservando todas las funciones de OpenSSH (SFTP, SOCKS, port forwarding, manejo de estado, roaming, etc.)
Me pregunto si OpenSSH podría aprovechar soporte del kernel
Ver Mosh
Probablemente sería mejor crear un protocolo de login aparte basado en QUIC
Ya hay varios enfoques en etapa de prototipo
Sin embargo, también se comenta que la implementación actual de QUIC en kernel es entre 3 y 4 veces más lenta que la de Linux, y que la diferencia de rendimiento se cerrará pronto
Si la ventaja de QUIC es la velocidad, pero en la práctica es más lento, entonces ¿cuál es el motivo para usarlo?
Incluso el autor del PR dice que parte de la pérdida de rendimiento viene del diseño del protocolo, así que pregunto si en TCP hay otros problemas que también necesiten corregirse
En su mayoría se pueden resumir como “todavía no lo han optimizado”
Por ejemplo, falta soporte para segment offload, hay copias de datos adicionales en la ruta de transmisión, y hay overhead por el cifrado de headers; todo eso tiene buenas posibilidades de solucionarse
Además, el benchmarking se hizo en un entorno muy idealizado
En la práctica, en entornos móviles la variabilidad de la red es alta, así que las limitaciones estructurales de TCP se vuelven mucho más evidentes
De hecho, muchos casos ya implementan sobre TCP funciones similares a las de QUIC, como hace HTTP/2
Al final, QUIC es un stack de networking integral que opera por encima de la capa 5 del modelo OSI, mientras que TCP es más bien un motor del nivel de la capa 3, así que compararlos estructuralmente no es sencillo
Sobre todo, la ventaja de QUIC está en conexiones y reconexiones más rápidas, y en garantizar continuidad de sesión incluso cuando cambia la IP
Su estructura de multiplexación y streams no bloqueantes simplifica de forma drástica el diseño de protocolos de nivel superior
Si esa arquitectura entra al kernel, también hay muchísimo margen para optimización de rendimiento
A futuro, en vez de seguir construyendo soluciones multicapa sobre las limitaciones de TCP, deberíamos usar más a diario tecnologías base más avanzadas como QUIC
Cuando hay pérdida de paquetes, todo lo que viene después se retrasa hasta que se recupere esa transmisión, así que tiene una limitación estructural importante por HOL blocking
No se trata solo de velocidad, sino de mejorar la latencia
Consulta este documento técnico
El principal cuello de botella está en los context switches entre kernel y espacio de usuario
El networking en user space (por ejemplo, acceso directo al NIC) elimina las entradas al kernel
Por otro lado, ofrecer funciones en espacio kernel (por ejemplo
sendfile, TLS en kernel, offloading del NIC, DMA directo del disco al NIC) también reduce los context switches totales y las copias de datosLos stacks QUIC actuales no aprovechan bien ninguna de las dos ventajas
La entrada y salida de paquetes sigue basada en syscalls y no puede evitar copias de datos
Con I/O por lotes usando io_uring y similares sí puedes reducir switches, pero no las copias en sí
Hay dos enfoques: kernel bypass + DMA, o excluir user space como en
sendfile/ktlsLa implementación de QUIC en kernel no tiene realmente ninguna de las dos ventajas
Si puedes escribir directo al NIC con DMA o si tienes que pasar por syscalls del kernel, la diferencia de rendimiento es grande
El networking en user space solo resulta convincente cuando existe esa estructura de transición de privilegios y DMA
Solo lo aprovechan empresas enormes (MOFAANG y similares)
En teoría se esperaba que io_uring generalizara esos beneficios, pero todavía no está en una etapa de uso real generalizado
Por eso TCP/IP sigue en el kernel en los principales sistemas operativos
Yo pensaba que el kernel debía encargarse de memoria, hardware y gestión de tareas; ¿no sería más correcto que los protocolos por encima de IP se procesaran en userland?
Por otro lado, separar esos stacks en user space también mejora el rendimiento en algunos casos
Como TCP/UDP arbitran en el kernel el routing de sockets por puertos, varios programas pueden usar TCP/UDP al mismo tiempo
QUIC funciona sobre UDP, así que el punto de la discusión sigue siendo válido
La observación es que lo que no se puede ejecutar en user space son solo los protocolos que van directamente sobre IP
Espero que internet se vuelva un poco más rápido a futuro
En entornos como 5G quizá no se note mucho la diferencia, pero sigue siendo un avance valioso
Me parece interesante que tenga una estructura separada de handshake de enlace
Yo pensaba que QUIC integraba TLS completamente dentro de sí, pero no era exactamente así
Aun así, creo que esta tecnología sí podría reducir más la latencia en juegos
Cuando mejoran los recursos de cómputo y la eficiencia de red, también aumenta la demanda
En juegos o cómputo científico eso no importa porque buscas “mejores resultados”
Pero en la web muchas veces tiene el efecto contrario por más anuncios, tracking y JavaScript
bind(),connect(),listen(),accept(), etc., como en TCP, pero luego cambia a una estructura basada en las syscallssendmsg()yrecvmsg()Me gustaría que también explicaran por qué eligieron ese enfoque y por qué no crear syscalls separadas específicas para QUIC