Calidad de servicio en GNU/Linux

ENLACES:

Linux Advanced Routing & Traffic Control


Cuando hablamos de calidad de servicio o QoS estamos hablando de un conjunto de mecanismos que nos van a permitir seleccionar el orden y la velocidad con la que se van a transmitir paquetes por un interfaz.

En entornos tipo Cisco es más sencillo, pero no porque sea más sencillo, sino porque quien trabaja en esos entornos está más acostumbrado a este tipo de conceptos sin embargo un administrador de sistemas tiene un espectro mucho más amplio de temas con los que trabaja a diario y su forma de pensar es más generalista.

La calidad de servicio es algo importante cuando hablamos de priorizar un tipo de tráfico sobre otro.

Antes de empezar comentaros que todo lo que voy a decir aquí lo tenéis en
Linux Advanced Routing & Traffic Control – lartc.org, además de las notas del programa en eduardocollado.com

En el programa de hoy voy a centrarme en las qdisc, es decir, las disciplinas de colas, las cuales afectan al tráfico saliente porque nosotros podemos decidir como enviamos el tráfico, pero difícilmente podemos decidir como otros nos envían a nosotros el tráfico, es muy importante tener esto claro.

Vamos a trabajar con colas, pero ¿qué es una cola?, pues lo que hacemos al subirnos al autobús.

Cuando queremos subirnos al autobús podemos hacer diversos tipos de cola, una por ejemplo sería una FIFO, el primero que llega es el primero que se sube al autobús, o incluso podríamos usar varias colas anidadas, por ejemplo podría haber dos colas, una para personas mayores y otra para el resto y nos pondríamos en fila en la fila que nos tocara, luego en el autobús primero subiría la cola de personas mayores y luego la de gente joven.

Si el autobús se llenara con la gente mayor, la gente joven no podría subir al autobús aunque hubieran llegado antes que los mayores, y así podríamos hacer lo que quisieramos con lo que el uso de colas podría pasar de una cola fifo facilita a un sistema más complicado.
El comando del día va a ser tc, que significa traffic control. Este comando se utilzar para configurar el control de tráfico en el kernel de linux y consiste en 4 cosas principalmene:

– shaping: cuando conformamos el tráfico lo que hacemos es modelarlo para evitar los picos y enviar esos picos de tráfico en momentos valle. Es para tráfico saliente. EXPLICAR ATM
– scheduling: consiste en reorganizar el tráfico para que un tráfico tenga una prioridad sobre otro. Solo funciona en tráfico saliente
– policing: es lo equivalente al shaping, pero en tráfico entrante
– dropping: la capacidad de tirar aquel tráfico sobrante, tanto en entrada como en salida.

El procesado de tráfico se realiza con tres tipos de objetos: qdiscs, clases y filtros.

Qdiscs: (Queue discipline) Un algoritmo que controla la cola de un dispositivo, sea de entrada (ingress) o de salida (egress)..
Clases: Las clases son qdisc hijas a otras qdisc principales o classless, es decir, se crea una jerarquía
Filtros: Es la selección de las clases dentro del qdisc classless.

Vamos a empezar con las configuraciones de las qdisc y con la pimera opción, que será configuración de pfifo_fast que no es modificable y es la que viene por defecto en algunas distribuciones, sin embargo en otras como ubuntu viene una qdisc con clase muy parecida.

Por defecto pfifo_fast tiene 3 bandas y procesa los paquetes según en la banda que estén.

tc qdisc add dev eth0 root pfifo_fast

Para borrar

tc qdisc del dev eth0 root

Para ver lo que hay en el interfaz

tc qdisc show dev eth0

La siguiente opción de colas será la Token Bucket Filter (TBF), y el funcionamiento se basa en tokens y en un buffer.

El funcionamiento consiste en que llegan tokens (bytes) que se van almacenando en el buffer hasta que se les da salida.

Para configurar esto

tc qdisc add dev eth0 root tbf

y luego

rate 2048kbit -> es decir 2Mbps
latency 50 -> es decir tiempo máximo para que los paquetes estén en la cola
burst 2048 -> tamaño del buffer para almacenar los picos, hay que poner 1kbyte por cada mbps.

tc qdisc add dev eth0 root tbf rate 2048kbit latency 50 burst 2048

Otra opción es Stochastic Fairness Queueing (SFQ), este es menos preciso, pero se calculan muy rápido los valores.

Este tipo de encolado lo que hace es crear un montón de colas y asignar cada conversación tcp o flujo udp a una cola diferente y luego round robin. De esta forma ninguna conversación va a afectar negativamente a las demás.

Es posible que varias conversaciones acabaran en la misma cola, así que para que esto no sea siempre así se va cambiando el algoritmo.

tc qdisc add dev eth0 root sfq

Y ahora

perturb 10 -> número de segundos a esperar para recalcular el hash de asignación de colas. Si no se pone nada no recalculará nunca
quantum 1522b -> por defecto un paquete con MTU máxima
limit 128p -> número de paquetes que serán encolados, luego serán descartados

se suele configurar solo el perturb:

tc qdisc add dev eth0 root sfq perturb 10

Una vez tenemos claras las qdisc sin clases, es interesante pasar a otro nivel más avanzado, las qdisc con clase.

La más conocida ( y antigua) es Class Based Queueing, conocida por sus siglas CBQ, es la más compleja y antigua, pero no tiene por qué ser la necesaria siempre.

Necesitaremos qdisc con clases cuando tenemos varios tipos de tráfico al que queremos tratar de forma diferente.

El tráfico entrará en una qdisc y ahí se llamará a un filtro que puede moverlo a otra qdisc

La qdisc PRIO subdivide el tráfico basándose en cómo haya configurado los filtros, algo parecido a la pfifo_fast, pero sepando en vez de en bandas en clases.

 

tc qdisc add dev eth0 root handle 1: prio
tc qdisc add dev eth0 parent 1:1 handle 10: sfq
tc qdisc add dev eth0 parent 1:2 handle 20: tbf rate 20kbit buffer 1600 limit 3000
tc qdisc add dev eth0 parent 1:3 handle 30: sfq

Usando bits de TOS de la cabecera de IP. The general idea is to map high priority packets into class 0, normal traffic into class 1, and low priority traffic into class 2.

Ahora pasamos a la CBQ

CBQ una de las cosas que hace es un shapping y eso lo hace calculando el porcentaje de tiempo que se puede usar el interfaz, por ejemplo si el interfaz es de 100Mbps y le decimos que el ancho de banda que se puede usar es de 10Mbps sólo utilizará el interfaz un 10% del tiempo y eso no implica necesariamente que estemos transmitiendo a 10Mbps, depende de muchos factures (drivers, interfaces virtuales….) y es ahí donde cojea CBQ enormemente.

Realmente CBQ utiliza el valor de tiempo ocioso para hacer sus cálculos, pero nos podría pasar cosas como por ejemplo que el enlace estuviera saturado y el tiempo ocioso fuera negativo.

Los parámetros para configurar CBQ son:

– avpkt: tamaño medio de paquete en bytes
– bandwith: ancho de banda físico del dispositivo.
– cell: número potencia de 2 que indica el tiempo en ser transmitido un paquete, normalmente 8
– maxburst: Se usa para calcular el maxidle, de forma que cuando maxidle llega a ser avgidle se puede enviar la ráfaga.
– rate: la velocidad (deseada) del qdisc

CBQ además también puede trabajar como PRIO y tener clases con diferentes prioridades, eso el sistema operativo lo gestiona con un proceso de WRR (Round Robin por peso), y para controlar ese WRR podemos usar los siguientes parámetros:

– allot: indica la cantidad de información que puede enviar cada clase cada vez que le toque el turno
– prio: le indica una prioridad a la clase
– weight: ayuda al WRR

Pero una de las características de CBQ más interesantes es la compartición y préstamo de ancho de banda entre clases.

– isolated: No prestará a sus hermanas
– bounded: No tratará de utilizar ancho de banda de otras clases hermanas

Ejemplo

tc qdisc add dev eth0 root handle 1:0 cbq bandwidth 100Mbit avpkt 1000 cell 8
tc class add dev eth0 parent 1:0 classid 1:1 cbq bandwidth 100Mbit rate 6Mbit weight 0.6Mbit prio 8 allot 1514 cell 8 maxburst 20 avpkt 1000 bounded
tc class add dev eth0 parent 1:1 classid 1:3 cbq bandwidth 100Mbit rate 5Mbit weight 0.5Mbit prio 5 allot 1514 cell 8 maxburst 20 avpkt 1000
tc class add dev eth0 parent 1:1 classid 1:4 cbq bandwidth 100Mbit rate 3Mbit weight 0.3Mbit prio 5 allot 1514 cell 8 maxburst 20 avpkt 1000

Y pasamos a HTB (Hierarchical Token Bucket). HTB comparaado con CBQ es algo maravilloso, mucho más intuitivo y sencillo, de hecho en mi caso no utilizo CBQ para nada, seguramente habrá algo que no lo cubra, pero, al menos yo no me lo he encontrado.

Los comandos serían

tc qdisc add dev eth0 root handle 1: htb default 12
tc class add dev eth0 parent 1: classid 1:1 htb rate 100kbps ceil 100kbps
tc class add dev eth0 parent 1:1 classid 1:2 htb rate 40kbps ceil 100kbps
tc class add dev eth0 parent 1:2 classid 1:10 htb rate 30kbps ceil 100kbps
tc class add dev eth0 parent 1:2 classid 1:11 htb rate 10kbps ceil 100kbps
tc class add dev eth0 parent 1:1 classid 1:12 htb rate 60kbps ceil 100kbps

rate: ancho de banda
ceil: ancho de banda máximo que puede tomar prestado

Y para no dejaros colgados con un tema un tema muy importante que es el de los filtos para saltar de una clase a otra

tc filter add dev eth0 protocol ip parent 10: prio 1 u32 match ip dport 22 0xffff flowid 10:1