¿Por qué los campos con prefijo de longitud se consideran hostiles al hardware?

Una crítica de GENEVE (un protocolo de encapsulación de red) es que utiliza campos de valor de longitud de etiqueta, y estos son difíciles de procesar en hardware.

¿Por qué se considera esto hostil al hardware? ¿Qué enfoques serían más amigables para la implementación de hardware de alta velocidad y por qué?

Respuestas (2)

Etiqueta (o tipo)-longitud-valor (TLV) es un método para contener diferentes tipos de información de longitud variable en una estructura de datos.

Solo necesita eso cuando no hay un subconjunto común de información que debe tener cada instancia de esa estructura de datos, o cuando el orden de los campos debe ser variable por algún motivo.

Piénselo de esta manera: si todos los paquetes GENEVE tenían un campo de "destino" que contenía, digamos, una dirección de red de 64 bits, ¿por qué no simplemente definir que cada paquete comienza con 64 bits de dirección de destino y ahorrarse una etiqueta y un campo de longitud?

El hardware (¡y eso incluye el hardware que ejecuta software!) es bueno para buscar valores en posiciones específicas. Entonces, analizar un encabezado donde la dirección de destino siempre está en la posición x y siempre tiene una longitud y es muy fácil; simplemente lee la dirección de memoria x e interpreta el resultado como un entero de longitud y. Eso es lo que hacen, por ejemplo, las CPU para cada cosa que leen de la RAM.

Si, por otro lado, para comprender un paquete, primero debe buscar campos específicos revisando los campos TLV (bueno, el primer campo dice que no es la etiqueta que estoy buscando, tiene una longitud de 14, así que avance 14 bits , ajá, no es el campo que estoy buscando, adelante,...) entonces analizar ese paquete será lento. Eso cuenta tanto para el software como para las implementaciones de hardware.

Incluso peor que lento, será de complejidad no determinista . Por lo tanto, algunas estructuras TLV pueden tomar solo un ciclo de reloj para analizar, otras necesitan iterar a través de 42 campos para hacer lo mismo. Si está implementando una aplicación de procesamiento de señales, tener en cuenta los retrasos aleatorios en uno de los pasos se convierte rápidamente en una pesadilla, ya que de repente necesita almacenar la entrada en el búfer, aplicar contrapresión o eliminar datos, solo porque alguien decidió tener una estructura de datos flexible. .

En el software, a menudo es económico y relativamente rápido preasignar una estructura de encabezado con compensaciones fijas y "completar" estos campos a medida que itera a través de la estructura TLV entrante. Pero: para eso, necesita RAM y, a menudo, bastante RAM, si no puede saber qué campos está buscando en el momento en que comienza a analizar la estructura.

Entonces, TLV es un esquema común para la serialización de datos débilmente estructurados para almacenamiento permanente o transmisión lenta. Por lo general, es bastante indeseable para las aplicaciones de transmisión, donde el mismo tipo de datos llega con bastante frecuencia (por ejemplo, paquetes de red, cuadros de video, comandos de operación de infraestructura...); en ese caso, preferiría predefinir estructuras fijas, incluso si eso desperdicia un poco de ancho de banda de transporte para campos ocasionalmente no utilizados.

Por ejemplo, la mayoría de los sistemas no utilizan todos los campos que puede tener un paquete Ethernet. Todavía no intentaría ahorrar dos bytes: transportar 1490 o 1492 bytes en Gigabit Ethernet no hace mucha diferencia, pero tener que verificar cada paquete individual si su paquete es de tipo A o tipo B tiene un impacto negativo.


@Janka plantea un punto importante: suponga que todo el trabajo de su hardware es solo copiar todo el paquete desde la entrada hasta la salida. Ahora, genial, en lugar de decirle a su motor DMA que copie un paquete de datos desde la entrada a la salida, está analizando todas las entradas para averiguar cuánto duran sus datos. Eso es mucho, mucho más lento que simplemente copiar datos.

+1, pero la respuesta muy corta es: DMA no analizará los datos, por lo que los campos de longitud no hacen más que agregar sobrecarga.
Bueno, @Janka, sí, esa es la forma abreviada de "donde otros pueden elegir una posición fija y una longitud de datos, el usuario de TLV primero tiene que analizar la estructura completa".
Todo esto es cierto, pero en comparación con casi cualquier otro patrón que permita una longitud variable o datos opcionales, TLV es eficiente, fácil de procesar y permite una extensión futura. En una escala de encabezados de ethernet a SQL para "fecha en una etiqueta de renovación en una placa capturada en un video de vigilancia", TLV se acerca mucho más al extremo más eficiente/amigable de la transmisión de datos.
El único TLV que conozco es cosas como Gzip o cualquier archivo de compresión variable. No es lo mismo que los datos normales o incluso los datos cifrados.
¡@Ben, por supuesto, tiene razón! Si tiene datos opcionales, no hay mucho que pueda hacer al respecto, pero téngalos en la parte posterior de sus campos obligatorios como tlv. El punto es que debes pensar qué es obligatorio y qué no.
@Sparky256: ASN.1 BER/CER/DER todos usan TLV (no es TLV "puro", porque una etiqueta puede introducir un registro que contiene múltiples campos no etiquetados individualmente) y está muy extendido en los protocolos de red.
¡Absolutamente! Pero: si su paquete consta principalmente de un campo, la etiqueta de ese campo se convierte efectivamente en "tipo de paquete"; si ese tipo de paquete introduce una estructura de registro fija, no tendrá los problemas que he descrito.
@MarcusMüller: Bueno, en ASN.1 algunos datos tienen una estructura de registro fija y minimizan las etiquetas incrustadas en algunas codificaciones, pero también se usan mucho las uniones, y cada vez que aparece una unión o una secuencia, obtienes más TLV. Y otras de las codificaciones etiquetan todo.

Además de la excelente respuesta de Marcus, solo agregaría que los campos con prefijo de longitud a menudo se consideran inferiores a los campos terminados porque requieren un contador adicional para procesar.

El ejemplo clásico son las cadenas C. Solo se requiere un único puntero para procesar una cadena porque solo se sigue incrementando el puntero hasta llegar al carácter de terminación nula. Con un prefijo de longitud, necesita un contador adicional para rastrear cuántos caracteres ha procesado, lo que significa más memoria y más procesamiento para seguir incrementándolo.

Puede parecer algo insignificante, pero en sistemas de muy baja potencia o de bajo costo o de baja especificación es importante.

OTOH, el código que procesa cadenas C a menudo necesita escanear la cadena una vez para encontrar la longitud y luego otra vez para procesarla. A veces se gana, se pierde algo.
Esa es la otra parte del diseño que necesita ser cuidadosamente considerada, para evitar la necesidad de hacerlo.