14.3. DSMARK

Esteve Camps

Este texto es un extracto de mi tesis sobre Soporte de QoS en Linux, septiembre de 2000.

Documentos fuente:

Este capítulo ha sido escrito por Esteve Camps <esteve@hades.udg.es>.

14.3.1. Introducción

Antes de nada, sería una buena idea leer los RFC escritos a este respecto (RFC2474, RFC2475, RFC2597 y RFC2598) que encontrará en el sitio web del Grupo de trabajo IETF DiffServ y el sitio web de Werner Almesberger (ha escrito el código para dar soporte en Linux a los Servicios Diferenciados).

14.3.2. ¿Con qué se relaciona Dsmark?

Dsmark es una disciplina de colas que ofrece las capacidades necesarias para los Servicios Diferenciados (también conocidos como DiffServ o simplemente DS). DiffServ es una de las dos arquitecturas QoS actuales (la otra se llama Servicios Integrados) que se basa en un valor transportado por los paquetes en el campo DS de la cabecera IP.

Una de las primeras soluciones en IP diseñadas a ofrecer algún nivel de QoS fue el campo Type of Service (el byte TOS) de la cabecera IP. Cambiando este valor, podíamos escoger un nivel alto/bajo de transferencia, retraso o fiabilidad. Pero esto no proporcionaba suficiente flexibilidad para las necesidades de los nuevos servicios (como las aplicaciones en tiempo real, las interactivas y otras). Tras esto, aparecieron nuevas arquitecturas. Una de ellas fue DiffServ, que mantuvo los bits TOS y los renombró como el campo DS.

14.3.3. Principios de los Servicios Diferenciados

Los Servicios Diferenciados están orientados al grupo. Quiero decir, no sabemos nada sobre flujos (éste es el propósito de los Servicios Integrados); sólo sabemos sobre agregaciones de flujos y aplicaremos diferentes comportamientosdependiendo a qué agregación pertenezca un paquete.

Cuando llega un paquete a un nodo exterior (edge node - nodo de entrada a un dominio DiffServ) entrando a un Dominio DiffServ, tendremos que controlar, ajustar o marcar estos paquetes (el marcado se refiere a asignar un valor al campo DS; exactamente igual que con las vacas :-) ). Esta será la marca/valor que mirarán los nodos internos de nuestro Dominio DiffServ para determinar qué comportamiento o nivel de QoS aplicar.

Como puede deducir, los Servicios Diferenciados implican un dominio dentro del cual se deberán aplicar todas las reglas de DS. En realidad, puede pensar que voy a clasificar todos los paquetes que entran en mi dominio. Una vez que entran todos estarán sujetos a las normas que mi clasificación dicta y cada nodo que atraviesen aplicará ese nivel de QoS.

En realidad, se pueden aplicar normas propias en los dominios locales, pero se deben tener en cuenta algunos Acuerdos de nivel de servicio (Service Level Agreements) cuando se conecta a otros dominios DS.

En este punto, debe tener muchas preguntas. DiffServ es más de lo que he explicado. En realidad, entenderá que no puedo resumir más de 3 RFC en sólo 50 líneas :-).

14.3.4. Trabajar con Dsmark

Como especifica la bibliografía de DiffServ, diferenciamos entre nodos externos (o limítrofes) e internos. Son dos puntos importantes en el camino del tráfico. Ambos tipos realizan una clasificación cuando llega el paquete. Su resultado puede usarse en diferentes lugares a lo largo del proceso de DS antes de que se envié el paquete a la red. Es por esto que el código de diffserv proporciona una estructura llamada sk_buff, que incluye un campo nuevo llamado skb->tc_index donde almacenaremos el resultado de la clasificación inicial que puede usarse en varios momentos del tratamiento DS.

El valor de skb->tc_index lo establecerá inicialmente la qdisc DSMARK, sacándola del campo DS de la cabecera IP de cada paquete recibido. Aparte, el clasificador cls_tcindex leerá todo o parte del valor de skb->tcindex y lo usará para escoger las clases.

Pero antes que nada, echemos un vistazo a la orden de la qdisc DSMAR y sus parámetros:

... dsmark indices INDICES [ default_index INDICE_DEFECTO ] [ set_tc_index ]
¿Qué significan estos parámetros?

Veamos el proceso de DSMARK.

14.3.5. Cómo trabaja SCH_DSMARK.

Esta qdisc seguirá los siguientes pasos:

                         skb->ihp->tos
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - >
     |                                                       |     ^
     | -- Si declara set_tc_index, almacenamos el            |     |  <-----Puede cambiar
     |    valor de DS en la variable skb->tc_index           |     |O       el campo DS
     |                                                      A|     |R
   +-|-+      +------+    +---+-+     Qdisc     +-+     +---N|-----|----+
   | | |      |filtro|--->|   | |-->  . . .  -->| |     |   D|     |    |
   | | |----->|índice|--->|   | |    Interna    | |---->|    v     |    |
   | | |      | tc   |--->| | | +---------------+ |   ---->(másc,valor) |
-->| O |      +------+    +-|-+--------------^----+  /  |  (.  ,  .)    |
   | | |          ^         |                |       |  |  (.  ,  .)    |
   | | +----------|---------|----------------|-------|--+  (.  ,  .)    |
   | | sch_dsmark |         |                |       |                  |
   +-|------------|---------|----------------|-------|------------------+
     |            |         | <- tc_index -> |       |
     |            |(leer)   |  puede cambiar |       |  <--------------Indice a la
     |            |         |                |       |                    tabla de pares
     v            |         v                v       |                    (másc,valor)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->
                         skb->tc_index

¿Cómo se marca? Cambie la máscara y el valor de la clase que quiere remarcar. Vea la siguiente línea de código:

tc class change dev eth0 classid 1:1 dsmark mask 0x3 value 0xb8
Esto cambia el par (másc,valor) de la tabla hash, para remarcar paquete que pertenecen a la clase 1:1. Tiene que "cambiar" estos valores por los valores por defecto que obtiene inicialmente (másc,valor). (Vea la tabla más adelante)

Ahora, explicaremos cómo funciona el filtro TC_INDEX y cómo cuadra en todo esto. Además, se puede usar el filtro TC_INDEX en otras configuraciones aparte de las que incluyen servicios DS.

14.3.6. Filtro TC_INDEX

Esta es la orden básica para declarar un filtro TC_INDEX:

... tcindex [ hash TAMAÑO ] [ mask MASCARA ] [ shift SHIFT ]
            [ pass_on | fall_through ]
            [ classid CLASSID ] [ police ESPEC_NORMA ]
Luego, mostramos unos ejemplos para explicar el modo de operación de TC_INDEx. Preste atención a las palabras resaltadas: tc qdisc add dev eth0 handle 1:0 root dsmark indices 64 set_tc_index tc filter add dev eth0 parent 1:0 protocol ip prio 1 tcindex mask 0xfc shift 2 tc qdisc add dev eth0 parent 1:0 handle 2:0 cbq bandwidth 10Mbit cell 8 avpkt 1000 mpu 64 # class de tráfico EF tc class add dev eth0 parent 2:0 classid 2:1 cbq bandwidth 10Mbit rate 1500Kbit avpkt 1000 prio 1 bounded isolated allot 1514 weight 1 maxburst 10 # qdisc fifo de paquetes para tráfico EF tc qdisc add dev eth0 parent 2:1 pfifo limit 5 tc filter add dev eth0 parent 2:0 protocol ip prio 1 handle 0x2e tcindex classid 2:1 pass_on (Este código no está completo. Es sólo un extracto del ejemplo EFCBQ incluido en la distribución de iproute2).

Antes de nada, supongamos que recibimos un paquete marcado como EF. Si lee el RFC2598, verá que el valor DSCP recomendado para el tráfico EF es 101110. Esto significa que el campo DS será 101110 (recuerde que los bits menos significativos en el byte TOS no se usan en DS) o 0xb8 en código hexadecimal.

              FILTRO
              TC INDEX
   +---+      +-------+    +---+-+    +------+                +-+    +-------+
   |   |      |       |    |   | |    |MANEJA|  +-+    +-+    | |    |       |
   |   |----->| MASC  | -> |   | | -> |FILTRO|->| |    | | -> | | -> |       |
   |   |  .   | =0xfc |    |   | |    |0x2E  |  | +----+ |    | |    |       |
   |   |  .   |       |    |   | |    +------+  +--------+    | |    |       |
   |   |  .   |       |    |   | |                            | |    |       |
-->|   |  .   | SHIFT |    |   | |                            | |    |       |-->
   |   |  .   | =2    |    |   | +----------------------------+ |    |       |
   |   |      |       |    |   |       CBQ 2:0                  |    |       |
   |   |      +-------+    +---+--------------------------------+    |       |
   |   |                                                             |       |
   |   +-------------------------------------------------------------+       |
   |                          DSMARK 1:0                                     |
   +-------------------------------------------------------------------------+

Entonces llega el paquete con el valor del campo DS puesto a 0xb8. Como explicamos anteriormente, la qdisc dsmark identificada por el id 1:0 en el ejemplo toma el campo DS y lo almacena en la variable skb->tc_index. El siguiente paso del ejemplo corresponde al filtro asociado con esta qdisc (segunda línea del ejemplo). Esto realizará las siguientes operaciones:

Valor1 = skb->tc_index & MASK
Clave = Valor1 >> SHIFT

En el ejemplo, MASC=0xFC i SHIFT=2.

Valor1 = 10111000 & 11111100 = 10111000
Clave = 10111000 >> 2 = 00101110 -> 0x2E en hexadecimal

El valor de recotno corresponderá a un controlador de filtro de una qdisc interna (en el ejemplo, el identificador 2:0). Si existe un filtro con este id, se verificarán las condiciones de control y medida (en caso de que el filtro las incluya) y se devolverá y almacenará en la variable skb->tc_index el classid (en nuestro ejemplo, classid 2:1).

Pero si se encuentra un filtro con ese identificador, el resultado dependerá de la declaración de fall_through. Si la hay, se devolverá como classid el valor clave. Si no, se devuelve un error y continúa el proceso con el resto de filtros. Sea cuidadoso si usa fall_through; se puede hacer si existe una relación simple entre los valores de la variable skb->tc_index y el id de la clase.

Los últimos parámetros que hay que comentar son hash y pass_on. El primero se refiere al tamaño de la tabla hash. Pass_on se usa para indicar que si no se encuentra un classid igual al resultado de este filtro, se debe intentar con el siguiente filtro. La acción por defecto es fall_through (vea la siguiente tabla)

Por último, veamos qué valores posibles se pueden dar a todos estos parámetros de TCINDEX:

Nombre TC               Valor           Por defecto
-----------------------------------------------------------------
Hash                    1...0x10000     Dependiente de la implementación
Mask                    0...0xffff      0xffff
Shift                   0...15          0
Fall through / Pass_on  Flag            Fall_through
Classid                 Mayor:menor     Nada
Police                  .....           Nada

Este tipo de filtro es muy poderoso. Es necesario explorar todas sus posibilidades. Más aún, este filtro no se usa sólo en las configuraciones con DiffServ. Lo puede usar como cualquier otro tipo de filtro.

Recomiendo que mire todos los ejemplos de DiffServ que se incluyen en la distribución de iproute2. Prometo que trataré de completar este texto lo más pronto que pueda. Además, todo lo que he explicado es el resultado de muchas pruebas. Le agradecería que me dijese si me he equivocado en algún momento.