HowTo: QoS, Calidad de servicio fácil en Linux.

Calidad de servicioAyer leyendo Un Sanjuanino en Rio Cuarto me dí con una entrada mencionando un vínculo a HowtoForge donde se plantea la alternativa mas facil que he visto hasta ahora para tener una implementación de QoS (por Quality of service en inglés: calidad de servicio) que aunque rudimentaria es totalmente funcional.

Se puede extender a cualquier otra disciplina de encolado y mejorar en función de las necesidades de cada uno, así que vamos a los bifes.

Requisitos necesarios:

  • Kernel con soporte para iptables.
  • Iptables instalado.
  • El comando tc instalado, que es parte del paquete iproute2
  • Opcional, l7filter para iptables.

Cualquier distribución orientada a servidor/router o redes en general ya trae estos tres requisitos preinstalados y configurados. En caso de no ser así basta con usar el gestor de paquetes de cabecera para instalar iproute2 e iptables, y seguir cualquier guía de configuración del kernel para darle soporte a iptables.

Esquematizando un poco:

El esquema de mi red es exactamente el mismo del ejemplo de howtoforge:

[internet]<–>[cablemodem]<–>[eth1  linux  eth0]<–>[red local]

Queda en cada uno adaptar las siguientes instrucciones para la topología de su red.

Implementación:

Todos los paquetes en su cabecera pueden contener o no el bit indicador de tipo de servicio (de ahora en mas ToS por Type of Service en inglés). Hay en total cuatro tipos de servicio que se pueden combinar entre sí en la práctica (aun que no debería hacerse en la teoría):

  • 0x02: Minimize Monetary Cost | Minimizar costo monetario
  • 0x04: Maximize Reliability | Maximizar fiabilidad
  • 0x08: Maximize Throughput | Maximizar tasa de transferencia
  • 0x10: Minimize Delay | Minimizar latencia

De la combinación de estos cuatro ítems surge un total de 16 combinaciones de ToS posibles, en hexadecimal:

  1. 0x00: No se especifica el bit ToS
  2. 0x02: Mimimize Monetary Cost (MMC)
  3. 0x04: Maximize Reliability (MR)
  4. 0x06: MMC + MR
  5. 0x08: Maximize Throughput (MT)
  6. 0x0a: MT + MMC
  7. 0x0c: MT + MR
  8. 0x0e: MT + MR + MMC
  9. 0x10: Minimize Delay (MD)
  10. 0x12: MD + MMC
  11. 0x14: MD + MR
  12. 0x16: MD + MMC + MR
  13. 0x18: MD + MT
  14. 0x1a: MD + MT + MMC
  15. 0x1c: MD + MT + MR
  16. 0x1e: MD + MT + MR + MMC

Que obviamente no es necesario recordar, pero que viene bien para entender mejor la sintaxis del comando tc mas adelante.

Creación de la disciplina de encolado raíz (qdisc root):

tc qdisc add dev eth1 root handle 1: prio priomap 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 0

La disciplina de encolado prio crea por defecto 3 colas, numeradas del cero al dos.

Priomap está enviando todo el tráfico que tenga activado los bits ToS de las primeras ocho combinaciones posibles –desde 0x00 hasta 0x0e– a la tercera cola (cola número 2) y  las siguientes siete combinaciones –desde 0x010 hasta 0x1c– en la segunda cola (cola número 1).

Todo el tráfico que tenga el bit ToS marcado como 0x1e irá a parar a la primera cola, la cero.

Hasta que no se vacía la primera cola, no se le da paso a la segunda cola, y hasta que no se vacía esta última no se le da paso a la tercera cola.

El howto a continuación agrega stochastic fairness queueingque encabeza el top-ten de las cosas complicadas que he memorizado en mi vida– a cada una de las colas prio para que estas tengan además una disciplina de encolado por si misma:

tc qdisc add dev eth1 parent 1:1 handle 10: sfq

tc qdisc add dev eth1 parent 1:2 handle 20: sfq

tc qdisc add dev eth1 parent 1:3 handle 30: sfq perturb 10

Como la tercera cola es la que alojará todo el tráfico sin clasificar, se reconfigura el hash cada 10 segundos usando perturb 10. Con suerte, todo el tráfico p2p saltador de puertos –que hace las delicias del administrador de red promedio– irá a parar a esta cola.

Solo resta comenzar a clasificar el tráfico de alguna forma para que los servicios mas interactivos (SSH, World of Warcraft, Counter Strike, VoIP, etc…) vayan por la primera cola, el resto del tráfico «no-tan-importante» por la segunda cola, y todo el tráfico «bulk», p2p y demás porquerías por la tercera cola.

Esto se puede conseguir de dos formas, con tc o con iptables.

Usando tc para clasificar el tráfico:

Ejemplo 1: Todo el tráfico que tenga como origen o destino el puerto 22 (SSH), por la primera cola:

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

tc filter add dev eth1 protocol ip parent 1: prio 1 u32 match ip sport 22 0xffff flowid 1:1

Y todo lo que tenga como origen el puerto 80 (HTTP), por la segunda cola:

tc filter add dev eth1 protocol ip parent 1: prio 1 u32 match ip sport 80 0xffff flowid 1:2

Ejemplo 2: Todo el tráfico que genera el host 192.168.0.150 por la primera cola:

tc filter add dev eth1 protocol ip parent 1: prio 1 u32 match ip src 192.168.0.150 flowid 1:1

tc filter add dev eth1 protocol ip parent 1: prio 1 u32 match ip dst 192.168.0.150 flowid 1:1

Y así sucesivamente, por número de IP o por número de puerto, adaptándolo a sus necesidades.

Marcando el bit ToS con iptables:

La otra posibilidad es usar iptables dentro de la tabla mangle para modificar los paquetes al vuelo, habilitándole a cada uno el bit ToS correspondiente según sus necesidades.

Ejemplo 1: Tráfico SSH, por la primera cola se ha dicho! (marcado como 0x1e)

iptables -t mangle -A PREROUTING -p tcp –dport ssh -j TOS –set-tos 0x1e

iptables -t mangle -A PREROUTING -p tcp –sport ssh -j TOS –set-tos 0x1e

¿Descargas de rapidshare? A la segunda cola!:

iptables -t mangle -A PREROUTING -p tcp -sport 80 -j TOS –set-tos 0x10

Por supuesto que estos son solo ejemplos, habrá quien prefiera dejar HTTP para el final y priorizar otros servicios…

Ejemplo 2: El tráfico que genera 192.168.0.150 a la primera cola:

iptables -t mangle -A PREROUTING -s 192.168.0.150 -j TOS –set-tos 0x010

Frutillita del postre o ejemplo 3: Teniendo instalado l7filter se pueden hacer cosas como esta, indistintamente del número de puerto o número de IP:

iptables -t mangle -A PREROUTING -m layer7 –l7proto edonkey -j TOS –set-tos 0x02

Y asegurarnos de esta forma de que emule, edonkey, mldonkey y cuanto otro clon exista en nuestra red, vayan siempre por la tercera cola, por tener seteado el bit 0x02.

O este otro:

iptables -t mangle -A PREROUTING -m layer7 –l7proto worldofwarcraft -j TOS –set-tos 0x1e

Para asegurarnos la mas baja latencia –el menor ping, como dicen los gamers– posible en el juego en cuestión.

Para ver la lista de protocolos soportados por l7filter, visitar la página web del proyecto.

Cualquier duda, sugerencia, correción, critica destructiva, etc, no duden en comentar.

18 comentarios

    1. Cuando dije que no creo en la calidad de servicio me refería a la _eterna polémica_ sobre si los tráficos de red deberían de tener «prioridades» según de qué tipo sean.
      Posiblemente la mayoría de vosotros lo entendiera, pero quizás otros no comprendieron la intención del comentario.

  1. Buen manual tio !

    Estoy pensando en preparar una máquinita con gentoo para hacerlo de router, ya qué, el que tengo, esta funcionando con brazilfw, pero me gustaria que no fuera «tan fácil» jeje.

    Un saludo y gracias por este tutorial, nos vemos en el foro man !

  2. Bueno, si te vas a enredar en tan tediosa tarea, mis condolencias desde ya, por que como dicen en Argentina, en tu caso supongo que será «un dolor de bolas».

    Nos vemos por allí, muchas gracias zapa, pero los méritos no son míos, solo traduje (y lo probé en mi router).

    Saludos!

  3. Que va, voy a disfrutar implementado esto en un equipo de gentoo haciendo de router.

    Ya qué, estoy queriendo aprender iptables (que voy muy poco a poco), y esto creo que me ayudará.

    Lo único que sé, es que, buscando lo fácil (como lo tengo actualmente con brazilfw), no se aprende nada, que con 2 clicks funcionen las cosas no es lo mejor para aprender la verdad.

    Me pondré manos a la obra, voy a hacer una nueva instalación de gentoo. Lo dejaré listo como router y me pondré a realizár qos manualmente con iptables, con esto seguro que iré ganando conocimientos sobre iptables.

    Un saludo y lo dicho, nos vemos por el foro man.

    1. Bienaventurado aquel que dispone del tiempo para dedicarle, por que de él será el reino de los que entienden de redes.

      Si te sirve el dato, el mas pequeño de los routers que armé con Gentoo y que funciona al día de hoy sin problemas (aun que no lo volvería ha hacer ni loco) corre en un pentium mmx de 200Mhz con 64mb de ram y un disco de 2Gb. Le sobra hardware por todos lados, corre un kernel 2.6.16 que era lo último en aquella época, y hace QoS con SPI usando l7filter (cuando no era userspace).

      Así que con cualquier pc que sea mejor que eso vas sobrado seguro.

      Saludos! (Y por lo del avatar, es verdad, te favorece :D)

  4. Hola, MalditoNerd (Buen nombre) llegue hasta acá buscando la forma de reutilizar un notebook que tiene la pantalla mañana se me ocurrió la idea de utilizarlo como router y a su ves poder gestionar el ancho de banda que ocupa el personal de la empresa en paginas de ocio (youtube, facebook…) a su ves seria liberarme de las limitaciones que trae el router de entel (chile) por defecto.
    Mis dudas son si por medio de este procedimiento podría lograr lo que busco? Teniendo un notebook con un solo puerto de ethernet (leí por allí que se pueden virtualizar las dos tarjetas de red).
    Espero que no sea demasiado tarde para poder comentar en este tema.
    Por otro lado gracias por compartir.

  5. Hola. Efectivamente. Lo que querés hacer es viable y se puede utilizar el método que planteo en este post. Lo que intentas hacer se llama RoS (router on a stick) y te va a servir de punta del ovillo para empezar a googlear al respecto.

    Si no te das maña con routing en Linux te recomiendo utilizar algún frontend amigable tipo shorewall o aún más amigable tipo ufw, al menos para la parte que a routear concierne.

    1. Wou! Muchas gracias por la respuesta al menos se que voy en buen camino.
      Con respecto a darme maña con el routing de linux, no lo hago actualmente pero amo la consola, igual no esta mal la opción del frontend.
      Me gustaría mucho poder estar mas en contacto si puedes escríbeme a mi correo: [email protected].
      Saludos!
      Gracias de nuevo.

  6. Por frontend me refería a uno que te haga fácil la vida. Nada de entornos gráficos ni nada que puedas clickear. Googlealos, en ambos casos es todo vía CLI.

    Si estás recién empezando te recomiendo ufw de una. Traduce de humano a iptables muy fácilmente y si bien nunca lo utilice he escuchado siempre muy buenas críticas.

    1. Si había entendido mal a que te referías con Frontend en ese caso. Lo revisare.

      Si estoy dando mis primeros pasos en esta zona del monitoreo de redes y balanceo de cargas.

      Gracias de nuevo
      PD: Cuando sea grande espero ser como tu. (Jajaja)

  7. Buenas tardes. He configurado QoS en una Raspberry PI1, siguiendo este tutorial, y me he encontrado con un posible gazapo. A ver tu opinión.
    Cuando indicas puerto origen 80 debe ser un error. Al comprobar las estadísticas con «tc -s -d class show dev eth0», la cola 2 está siempre a cero, por mucho que cargue páginas web en el navegador. Al final, lo he dejado así:
    # Y todo lo que tenga como destino el puerto 80/443 (HTTP(S)), por la segunda cola:
    tc filter add dev eth0 protocol ip parent 1: prio 1 u32 match ip dport 80 0xffff flowid 1:2
    tc filter add dev eth0 protocol ip parent 1: prio 1 u32 match ip dport 443 0xffff flowid 1:2

    Dicho de otra forma, puerto de destino 80 (HTTP) y 443 (HTTPS) a la cola 2. Así sí se incrementa el contador de la cola 2 cuando cargo páginas web. Aunque no he puesto aquí los comandos, en la cola 1 (máxima prioridad) va la VoIP, y en la 3 el resto de tráfico. Con esa configuración me sobra, por ahora, para mi LAN. Ya iré depurando la configuración con el tiempo, pero tu post me ha venido muy bien como punto de partida.

    Una saludo y espero tu respuesta.

    1. Otro saludo y te vas a cagar esperando si pensás que me voy a poner a re-leer un artículo que escribí hace nueve años buscando si tiene algún error conceptual o de sintaxis.
      La implementación funciona. La utilicé decenas de veces. Si el post tiene algún problema está muy bien que lo hayas podido encontrar por tu cuenta y te felicito como así también te agradezco la intención de corregirlo. Tal vez le sirva a alguien más.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *