1 puntos por GN⁺ 2025-09-28 | 1 comentarios | Compartir por WhatsApp
  • 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

 
GN⁺ 2025-09-28
Comentarios en Hacker News
  • La parte clave del artículo está escondida a la mitad

    En casos extremos, en un benchmark limitado por CPU, mejoró de < 1 Gbit/s a 4 Gbit/s. En el flamegraph de CPU, la mayor parte del tiempo se consumía en llamadas al sistema de I/O y código de cifrado
    Que el rendimiento de red haya aumentado un 400% significa que el uso de CPU se redujo muchísimo en tráfico de red UDP
    Esto también resulta especialmente impresionante desde el punto de vista de la eficiencia energética en clientes portátiles como móviles y laptops
    A menudo se da por hecho que este tipo de transición siempre es buena, pero aquí se siente fresco porque el artículo lo demuestra con datos reales

    • Me pregunto si algún día el paso de mensajes entre el usuario y los programas del sistema, cruzando contextos, terminará funcionando con aceleración por hardware
  • 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 como uring, 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 leerlo

  • No 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

  • La parte donde, después de muchísimas idas y vueltas con quien reportó el problema (también empleado de Mozilla), al final hasta compraron una laptop del mismo modelo y color para poder reproducirlo
    Fue divertido porque mostró la loca realidad de reproducir problemas de red, justo como en XKCD 2259
    (enlace al cómic de xkcd)

    • 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

    • Me pregunto por qué Microsoft y Apple no ponen un poco más de atención en la calidad de sus stacks de red
      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

    • Por lo que entendí, a nivel de aplicación, incluso si GRO está activado, en realidad no se reciben datagramas UDP fusionados como tal
      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/recvmmsg sean 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_uring no tiene una capacidad de batching real para manejar varios datagramas UDP a la vez
      En el mejor de los casos, solo puedes pedir varios sendmsg y recvmsg al mismo tiempo
      GSO/GRO es la respuesta
      sendmmsg/recvmmsg ya son tecnologías bastante antiguas, e incluso hay desarrolladores del kernel que ahora quisieran eliminarlas
      (discusión relacionada en GitHub)