jueves, 21 de febrero de 2008

Policy Routing - Balance de carga

Este documento trata de explicar el uso de la técnica Policy Routing para balancear el tráfico hacia internet por dos o más salidas, antes de continuar voy a dejar la definición de algunos conceptos.

Policy Routing

Es la técnica que nos permite seleccionar la ruta que seguirá un datagrama según el origen, el direccionamiento ip en sus algoritmos de ruteo ( ej. RIP ) define el path del paquete según el destino que quiera alcanzar, lo que nos agrega Policy Routing es poder definir el path también mirando el origen.

Tabla de ruteo ( Route Table )

Tabla compuesta de reglas que le permite conocer y decidir a un router sobre el destino a seguir de los datagramas que reciba.
xxx@router:~$ ip route 10.10.11.0/24 via 192.168.202.2 dev eth1 192.168.202.0/24 dev eth1 proto kernel scope link src 192.168.202.1 default via 201.23.28.25 dev eth0

Este es un ejemplo de la salida de la tabla de ruteo, por lo general en los routers existe una única tabla de ruteo llamada main y con un único gateway ( en este ejemplo es el router con IP
201.23.28.25 )

Situación

Para mayor entendimiento voy a llevar el caso a una situación puntual de la práctica, donde tenemos un servidor GNU\Linux con 3 placas de red al cual queremos conectarle unos ADSL para alivianar la carga del enlace principal.

eth0: Conectado al acceso principal de internet
eth1: conectado a la red local
eth2: libre ( donde conectaremos los ADSL por medio de un switch )

Contrataremos más de 1 ADSL , porque algúns proveedores del servicio no funcionan del todo bien, por eso 2 o 3 es mejor, y además el caso se hace más complejo.

Requerimientos

Software de base: Debian Sarge ( 3.1 )
Herramientas: iptables , iproute

Objetivo

Lograr distribuir la demanda crítica de nuestra LAN por el enlace principal ( ej: Correo, Navegación ) y la carga no crítica por los ADSL ( ej: p2p, MSN entre otros ), haciendo dicha ingenieria de carga vamos a asegurar la usabilidad de los protocolos principales de una empresa.
Por lo general se llega a este tipo de distribuciones debido a que no se puede pedir ampliación del enlace principal, o por más que se defininar colas de prioridades sobre el enlace principal, éste tampoco alcanza.


Implementación con un ADSL


Lo primero a crear será una segunda tabla de ruteo, llamada adsl , la cual tendrá en su primer implementación, unicamente una regla,pero antes de llegar a ese paso vamos a describir desde el principio la configuración del adsl

El modem adsl es Router ademñas, lo que implica que la dirección IP pública estará en el router y nosotros por dhcp vamos a tener una ip privada que será nateada por el equipo, en primera instancia suponemos el ADSL conectado directamente a nuestra placa de red eth2.

Configuramos nuestra placa de red eth2 para que levante por dhcp entonces, tenemos algo como

xxx@router:~# ip addr add 10.0.0.1/30 dev eth2
xxx@router:~# ip addr eth2: mtu 1500 qdisc pfifo_fast qlen 1000 link/ether 00:16:17:9d:3d:b2 brd ff:ff:ff:ff:ff:ff inet 10.0.0.1/30 brd 10.255.255.255 scope global eth2 inet6 fe80::216:17ff:fe9d:3db2/64 scope link valid_lft forever preferred_lft forever
De la configuración obtenida por dhcp, deducimos facilmente que la IP del Modem ADSL es 10.0.0.2


Modem ADSL Listo, ¿ Ahora ?

Bien , ahora llegó la hora de crear nuestra tabla de ruteo llamada DSL donde el gateway será nuestro MODEM ( 10.0.0.2 ), la creamos de la siguiente manera

Editamos el archivo /etc/iproute2/rt_tables y agreegamos al final nuestra nueva tabla "dsl", nos quedaria

----------archivo rt_tables
#
# reserved values
#
255 local
254 main
253 default
0 unspec
#
# local
#
#1 inr.ruhep
1 dsl
------------

Ahora agregaremos las reglas a nuestra nueva tabla

xxx@router:~# ip route add 10.0.0.0/30 dev eth2 src 10.0.0.1 table dsl
xxx@router:~# ip route add default via 10.0.0.2 table dsl

Listamos si se creo correctametne nuestra tabla de ruteo adsl

xxx@router:
~# ip route show table dsl
10.0.0.0/30 dev eth0 scope link src 10.0.0.1
default via 10.0.0.2 dev eth0


Distribuir la carga

Luego de tener las 2 tablas de ruteo ( la main y dsl ) tenemos que determinar que tráfico se envierá por cada tabla.
Para eso, vamos a marcar con iptables los distintos tipos de tráfico, vamos a definir en el ejemplo dos tipos.
  • Tráfico A: correo / web
  • Tráfico B: p2p / msn / resto...
Marcamos tráfico B de la siguiente manera ( todo lo que no incluya correo o web ).

xxx@router:~# iptables -t mangle -A PREROUTING -p tcp -m multiport --dports ! 80,443,25,110 -i eth1 -s 10.10.11.0/24 -j MARK --set-mark 4

Como veran la marca se hace en el nivel de Transporte del modelo OSI.


Policy Routing

Al tener marcado el tráfico B , vamos a enviarlo por la tabla dsl, de esta manera dejamos el tráfico restante ( A ) sobre la tabla principal, el encargado de satisfacer la acción será iproute nuevamente.

xxx@router:~# ip rule add fwmark 4 table dsl
xxx@router:~# ip route flush cache

Verificamos que se haya cargado correctamente.

xxx@router:~# ip rule
0: from all lookup local
32765: from all fwmark 0x4 lookup dsl
32766: from all lookup main
32767: from all lookup default

Nota 1: La marca 0x4 se corresponde con la marca iptables
Nota 2: no usar marcas superior a 0x8 en iptables que no seran reconocidas por iproute.


Fin de la implementación, con herramientas como iptraf/iftop podemos ver el tráfico que circulará sobre nuestra placa conectada al adsl ( eth2 ).

Implementación con X ADSL

La implementación con varios ADSL se podría hacer conectando todos a un switch y la placa eth2 conectarla a dicho equipo, cada ADSL tendrá su propia red privada configurada por nosotros, por ejemplo.

ADSL 1: ip 10.0.0.2 / mascara 255.255.255.252

ADSL 2: ip 10.0.1.2 / mascara 255.255.255.252

ADSL 3: ip 10.0.2.2 / mascara 255.255.255.252

Nuestra placa eth2 ahora tendrá que tener 3 direcciones IP , una por cada ADSL

xxx@route:~# ip addr add 10.0.0.1/30 dev eth2 xxx@route:~# ip addr add 10.0.1.1/30 dev eth2 xxx@route:~# ip addr add 10.0.2.1/30 dev eth2

Balanceando carga en partes iguales para X ADSL

En un comienzo dije que por lo general solo tenemos 1 solo gateway por tabla, aquí nuestra tabla dsl tendrá X posibles salidas , es decir X gateways, donde se le dará un peso ( importancia ) a cada uno.

La idea ahora es enviar nuestro tráfico B por los ADSL , pero como se hace para que los 3 ADSL en nuestro ejemplo reciban una carga justa cada uno ??

Opción 1: crear 3 tablas ( adsl1 , adsl2 , adsl3 ) y enviar tráfico B1 B2 B3 ( hacer nuevas marcas dentro del tráfico B ), este procedimiento es bastante manual y puede que nos equivoquemos en distribuir a mano la carga para cada ADSL.

Opción 2: que se encargue Linux de distribuir la carga justa para cada ADSL ( eso es lo que voy a mostrar ).
xxx@route:~# ip route add default scope global table dsl nexthop via 10.0.0.2 dev eth2 weight 1 nexthop via 10.0.1.2 dev eth2 weight 2 nexthop via 10.0.2.2 dev eth2 weight 2

Fijarse que le damos un peso a cada gateway , al adsl 1 peso 1 y a los otros peso 2


Ventajas
  • El servidor balancea la carga con los 3 adsl según las entradas que vaya registrando en su tabla de ruteo.
  • Al darle un peso a cada gateway, se puede determinar mayor prioridad para algún adsl
  • Si se cae un ADSL, automaticamente Linux lo detecta y desvia el tráfico para los restantes vinculos, cosa que con la opción 1 no ocurre.
Sugerencias

  • Configurar los procedimientos en scripts para que se inicien automaticamente luego de reiniciado el servidor

  • Crear scripts que puedan verificar el estado del Modem ADSL y reinciarlo en caso de que la conexión a internet se haya cortado.

  • Instalar herramientas para monitorear el tráfico por cada ADSL, no es sencillo ya que la unica forma de determinar el trafico que proviene de cada ADSL es a través de la capa de Enlace por la MAC Address, mis sigerencias son pmacct y rrdtool para las gráficas.






miércoles, 2 de enero de 2008

Bienvenida

Me doy mi propia bienvenida al blog, aunque parezca demasiado "egocentrista" la oportunidad amerita que así sea...

No tengo todavía definido cuál será el contenido del blog, pero prefiero no apurarme y ver si realmente resulta útil para alguien al menos.