- Aproximadamente el 20% del tráfico HTTP de Firefox usa HTTP/3, que funciona sobre QUIC y UDP
- Al reemplazar NSPR, la capa existente de E/S de red, por quinn-udp basado en Rust, se reforzaron el rendimiento y la seguridad de memoria
- Se aplicaron optimizaciones de rendimiento aprovechando activamente llamadas al sistema modernas específicas de cada sistema operativo (multi-message, segmentation offloading, etc.)
- En Windows y macOS, algunas funciones quedaron limitadas por compatibilidad y problemas de drivers, pero en Linux se confirmó el mejor rendimiento
- La experiencia acumulada al resolver diversos problemas y bugs por plataforma relacionados con soporte de QUIC ECN y E/S UDP también podría beneficiar a proyectos futuros y al ecosistema open source
Motivación
- Aproximadamente el 20% del tráfico HTTP de Firefox usa HTTP/3, que opera mediante QUIC y, a su vez, está implementado sobre UDP
- Históricamente, Firefox usó la biblioteca NSPR para la E/S de red, pero sus funciones relacionadas con E/S UDP son antiguas y limitadas (las funciones principales son
PR_SendTo y PR_RecvFrom)
- Los sistemas operativos han incorporado recientemente llamadas al sistema de múltiples mensajes (p. ej.
sendmmsg, recvmmsg) y optimizaciones de red como segmentation offload (GSO, GRO)
- Estas tecnologías pueden mejorar significativamente el rendimiento de la E/S UDP
- Firefox exploró si podía obtener esos beneficios reemplazando su stack de E/S UDP existente por llamadas al sistema modernas
Resumen general
- El proyecto comenzó a mediados de 2024, con el objetivo de reconstruir el stack de E/S UDP de QUIC en Firefox con llamadas al sistema modernas en todos los sistemas operativos compatibles
- Además de mejorar el rendimiento, también se buscó aumentar la seguridad al usar Rust, que garantiza seguridad de memoria, en la E/S UDP
- Como QUIC ya estaba implementado en Rust, el desarrollo se realizó sobre la biblioteca quinn-udp basada en Rust
- Las diferencias entre llamadas al sistema según el sistema operativo elevaron la dificultad del desarrollo, pero quinn-udp mejoró notablemente la velocidad de implementación
- A mediados de 2025, el despliegue ya está en curso para la mayoría de los usuarios de Firefox, y en benchmarks de rendimiento mostró un gran aumento, de hasta 4 Gbit/s
Estructura de la E/S UDP y optimizaciones modernas
Envío de un solo datagrama
- El enfoque anterior usaba
sendto y recvfrom, enviando y recibiendo solo un datagrama UDP por vez
- El costo de cambiar entre espacio de usuario y espacio del kernel se pagaba por datagrama, lo que era ineficiente en entornos de tráfico de gran volumen
- Ejemplo: para enviar paquetes menores a 1500 bytes a varios cientos de Mbit por segundo, se generaba un overhead considerable
Envío por lotes de múltiples datagramas
- Linux y algunos otros sistemas operativos admiten llamadas al sistema multi-message como
sendmmsg y recvmmsg
- Al enviar y recibir varios datagramas de una sola vez, se puede reducir drásticamente el overhead
Un solo datagrama grande segmentado
- Tecnologías de offload como GSO (envío) y GRO (recepción) permiten transmitir un datagrama UDP grande segmentándolo automáticamente en el SO o en la NIC
- La interfaz de red se encarga de separarlo por paquetes, calcular checksums y adjuntar headers
- Gracias a esto, la aplicación puede procesar múltiples paquetes reales con una sola llamada al sistema
- Con GSO activado, algunas herramientas de red como Wireshark ofrecen soporte limitado para analizar paquetes
Proceso de reemplazo de NSPR en Firefox
- Primero se reemplazó NSPR por quinn-udp en la estructura de envío y recepción de un solo datagrama
- Se refactorizó el pipeline de procesamiento de datagramas de la implementación QUIC para soportar envío/recepción por lotes y segmentación
- Tanto las llamadas multi-message como las de segmentation offload se usan según corresponda
- Se añadieron manejo de excepciones por plataforma y varias mejoras de E/S
Detalles por plataforma
Windows
- Windows ofrece
WSASendMsg/WSARecvMsg, con soporte para datagramas del tamaño MTU tradicional o datagramas segmentados de gran tamaño
- Los equivalentes en Windows a GSO/GRO de Linux son USO (envío) / URO (recepción)
- Al principio, usar solo llamadas de datagrama único no causó problemas, pero al activar URO apareció un bug en ciertos entornos (por ejemplo, Windows on ARM + WSL) donde no era posible determinar la longitud de los paquetes QUIC, lo que provocaba fallas al cargar páginas
- También se usó USO/envío, pero se descubrieron efectos secundarios como aumento de pérdida de paquetes y crashes de drivers de red en entornos de instalación de Firefox para Windows
- Actualmente, Firefox mantiene URO/USO desactivados y continúa con la depuración adicional
macOS
- En macOS, se introdujo quinn-udp usando
sendmsg/recvmsg en lugar de sendto/recvfrom
- La funcionalidad de segmentation offload no está activada
- En su lugar,
sendmsg_x/recvmsg_x, que no están documentadas oficialmente, permiten envío por lotes, y se aplicaron de forma no oficial en quinn-udp
- Como Apple podría eliminar esas llamadas en el futuro, solo se probaron sin activarlas por defecto y no se incluyeron en la versión final
Linux
- Soporta tanto sendmmsg/recvmmsg como GSO/GRO, y quinn-udp prioriza GSO por defecto al enviar
- Firefox usa un socket UDP separado por conexión para reforzar la privacidad (distinción por 4-tuple)
- En esta estructura, la ventaja del segmentation offload se maximiza, mientras que los beneficios del envío cruzado con sendmmsg/recvmmsg son limitados
- Aparte de pequeños cambios como el sandbox de red y la verificación en tiempo de ejecución del soporte de GSO, la adopción se completó sin grandes dificultades
Android
- A diferencia de Linux, Android tiene una ruta de procesamiento de llamadas al sistema y filtros de seguridad (por ejemplo, seccomp) distintos
- Existen varios problemas de compatibilidad, como soporte para plataformas muy antiguas como Android 5 basado en x86, evasión de
socketcall y manejo de errores
- En algunos entornos, las llamadas de envío con bits ECN activados provocaban errores (EINVAL), por lo que quinn-udp aplicó una estrategia de reintento y desactivación de opciones
- Gracias a diversas mejoras dentro de la comunidad de Quinn, Firefox también puede beneficiarse automáticamente de esas mejoras
Soporte para ECN (Explicit Congestion Notification)
- Gracias a la adopción de llamadas al sistema modernas, se habilitó el envío y recepción de ancillary data, haciendo posible el soporte de QUIC ECN
- Hubo algunos bugs menores, pero en Firefox Nightly más de la mitad de las conexiones QUIC funcionaban con la ruta de salida ECN
- A medida que tecnologías nuevas como L4S cobran relevancia, también aumenta la importancia y utilidad del soporte para ECN
Resumen de conclusiones
- Se reemplazó la capa de E/S UDP de QUIC en Firefox por una implementación en Rust basada en quinn-udp, logrando al mismo tiempo rendimiento y seguridad
- En lugar de llamadas al sistema anticuadas, ahora se aprovechan las llamadas modernas de E/S de cada sistema operativo, lo que mejora el throughput y permite soporte para ECN
- Algunas funciones de optimización en sistemas como Windows todavía requieren mejoras adicionales por problemas de compatibilidad
- A medida que el uso de QUIC sigue creciendo, es probable que el soporte a nivel de sistema operativo y drivers continúe evolucionando
1 comentarios
Comentarios en Hacker News
La parte clave del artículo está escondida a la mitad
La mejora mencionada aquí sí es necesaria para velocidades realmente altas (más de 100 Gb/s), pero 4 Gb/s en realidad no es tan rápido
Son 500 MB/s, así que eso significa que hay algún cuello de botella gravemente lento
Dicen que el cambio de contexto del kernel está en el rango de 1 us, lo cual en realidad es alto para una llamada al sistema
Aun así, con un promedio de apenas unos 500 bytes por paquete ya se pueden alcanzar 500 MB/s, es decir, 4 Gb/s
El antiguo 1 Gb/s era cuando el tamaño de paquete era más pequeño, y meter paquetes UDP directamente al búfer de la NIC es algo que incluso la velocidad de copia de memoria puede manejar sin problema
Aunque el cifrado fuera lento, en la práctica no lo es
Por ejemplo, un Intel i5-6500 llegó a 1729 MB/s en AES-128 GCM
Los CPU actuales pueden hacer 3-5 GB/s por núcleo, o sea 25-40 Gb/s, así que esos 4 Gb/s de los que hablan son demasiado bajos
(enlace de referencia de rendimiento AES-128 GCM)
Mencionaste que la latencia de la llamada al sistema es alta, y la causa podría ser las mitigaciones contra spectre & meltdown
TCP tiene binding de ruta, pero UDP no, así que hay una gran diferencia en la forma de configurar la ruta
Decir que el cifrado es lento sí aplica en PDU pequeñas (unidad de datos de protocolo)
Casi todo está optimizado y benchmarkeado en función de tramas TCP grandes, así que en paquetes pequeños el costo de preparar el estado realmente se nota
Si haces microbenchmarks en un tight loop los números salen bien, pero en entornos reales con aleatoriedad la eficiencia de caché baja, y con paquetes menores a 1 KB el rendimiento se desploma
A eso súmale overhead adicional de framing, validación de datos fuera de banda y otras cosas que resultan bastante costosas
La memoria de búfer UDP también se queda corta con los valores por defecto, lo cual da muchos problemas en uso real
Operando TCP fuimos aumentando el tamaño de los búferes constantemente, pero UDP sigue atascado en valores conservadores de los 90 y 2000
La API que de verdad hace falta debería permitir hacer fork del fd, soporte completo para
connect(2)y route binding, y luego una submission queue comouring,rio, etc.En el frente del cifrado, un enfoque basado en KDF puede reducir mucho el costo de estado
El enfoque PSP es aceptado por algunos vendors, pero en IETF y otros lados lo han rechazado bastante, así que no se ha difundido ampliamente
En pruebas de concurrencia masiva de varios vendors, escala muchísimo mejor que variantes tradicionales tipo TLS
No dicen en absoluto de qué clase era el CPU usado en el benchmark
Y el overhead de cifrado es en realidad el costo de procesamiento del propio protocolo QUIC
QUIC tiene menos soporte de offload de cifrado (procesamiento por hardware) que TCP, mientras que TCP al menos puede descargar parte del trabajo a la NIC con offload de kTLS
Este tipo de contenido técnico realmente me dejó muy satisfecho
Ojalá todo el material técnico de Mozilla tuviera esta profundidad y estuviera escrito así de bien por ingenieros con experiencia real
Sin optimismo vacío (
alegria) ni nada por el estilo; vale mucho la pena leerloNo entiendo por qué siguen dando soporte a Android 5
Salió hace más de 10 años, y los usuarios que todavía usan esos dispositivos ya son legado todavía más viejo
La web de hoy es demasiado pesada, así que ni siquiera debe ser fácil navegar bien con esos equipos tan antiguos; de verdad me pregunto por qué siguen soportándolos
Probablemente sean solo hackers que restauran dispositivos viejos como algún OnePlus antiguo, lo dejan enchufado al cargador, ni siquiera le ponen una ROM popular como LineageOS y usan Firefox desde una tienda de apps alternativa
En la práctica, eso solo ralentiza la velocidad total de desarrollo
También recomiendo un episodio interesante relacionado en el blog de desarrollo de Factorio llamado "The map download struggle"
(entrada relacionada del blog)
Cualquiera que haya tratado problemas de red de verdad se va a identificar todavía más por culpa de los misteriosos packet runts
La mayoría de los equipos de red no manejan bien este tipo de paquetes
El tráfico basado en UDP o QUIC es fácilmente vulnerable a ataques salvo en entornos de nube grandes por encima de cierto nivel
Por eso cada vez es más difícil operar para hostings pequeños o autogestionados, y al final solo sobreviven los que tienen capacidad para manejar tráfico a gran escala
Así que en la mayoría de los entornos LAN están descartando casi todo el tráfico UDP y solo procesan lo necesario con rate limiting
Bug tracker de Mozilla
En macOS y Fedora sigo teniendo el mismo problema al entrar a sitios alojados por Cloudflare usando Firefox
Recién me enteré de que Windows y macOS también tienen funciones parecidas a GSO/GRO (procesamiento de paquetes de red grandes)
Lástima que al parecer en la práctica tienen bastantes bugs
También me da la impresión de que GSO/GRO no debe ser lo único que tiene bugs
Preguntan si alguien puede explicar cómo funciona estructuralmente UDP GSO/GRO
UDP no tiene orden de paquetes, así que cuando un paquete QUIC se divide en varios paquetes UDP y el header no lleva información de secuencia, me da curiosidad cómo hace el receptor para volver a unirlos en orden
La idea es que el kernel mete varios datagramas en una sola estructura y los pasa manteniendo los límites entre capas (por ejemplo, data fragments dentro de
sk_buff)No soy un experto exacto en esto, pero buscando cómo funciona terminé consultando este artículo
Mencionan que “empezamos el desarrollo sobre
quinn-udp, la biblioteca de UDP I/O del proyecto Quinn, y eso aceleró muchísimo el desarrollo”Entonces me pregunto si habrán apoyado económicamente al proyecto Quinn
(enlace de apoyo a Quinn)
Pregunté directamente sobre el apoyo financiero, y un Senior Principal Software Engineer de Mozilla respondió: "Mozilla no tiene dinero"
Aun así, han contribuido muchísimo código y eso se agradece de verdad
(Yo soy maintainer principal de Quinn)
Ante la pregunta de “¿donaron?”, alguien opinó que el estilo de Mozilla es no apoyar el open source y en cambio gastar varios millones de dólares más en el salario del CEO
Eso mientras hasta su producto insignia (Firefox) se está viniendo abajo
Me da curiosidad saber si contribuyeron de otras formas, como con código
Sorprende que
sendmmsg/recvmmsgsean llamados “modernos”En realidad son llamadas al sistema que existen desde hace bastante tiempo
También esperaba que en el contenido relacionado con Linux mencionaran
io_uring, pero faltóio_uringno tiene una capacidad de batching real para manejar varios datagramas UDP a la vezEn el mejor de los casos, solo puedes pedir varios
sendmsgyrecvmsgal mismo tiempoGSO/GRO es la respuesta
sendmmsg/recvmmsgya son tecnologías bastante antiguas, e incluso hay desarrolladores del kernel que ahora quisieran eliminarlas(discusión relacionada en GitHub)