MANUAL: Mikrotik, balanceo de carga PCC con failover

Introducción

Hoy vamos a hablar de un tema la mar de interesante, si bien no es demasiado usado a nivel doméstico. Se trata del balanceo de carga con failover. Básicamente cómo aprovechar tu conexión, cuando tienes dos líneas de internet.

Propósito

El propósito de este manual viene de una nueva necesidad: trabajo de normal desde casa y llevaba tiempo con el runrun de poner una segunda conexión a internet. Normalmente, cuando fallaba mi querido Pepephone (todas fallan alguna vez), tiraba de la conexión móvil. Pero, dado que vivo en una zona con escasa cobertura, cumplir con mi trabajo se me hacía complicado usando este tipo de conexión. Esto, unido a que derivado de la pandemia la situación en casa ha cambiado y ya no soy yo sólo el que trabaja en remoto, me hizo plantearme que no sería nada descabellado tener una segunda conexión a internet (dos fibras) por si, $deity no lo quiera, mi querido Pepephone me dejaba tirado en algún momento. Estudiadas las ofertas y haciendo números, opté por contratar con o2, de la cual ya tenía buenas referencias por un par de instalaciones en casa de familiares. Además de esto, en mi casa ya existía una toma de fibra de telefónica, que Pepephone respetó cuando instaló la suya, así que supuse que iba a ser coser y cantar. Dicho y hecho, el móvil costó un poco más, pero la fibra estaba instalada al día siguiente de pedirla. Y ahora viene cuando pokoyo se pregunta, ¿qué coj_nes hago yo con dos líneas de 600, cómo las aprovecho? Porque, si ya me parecía burra la de 300 simétricos, ahora con dos de 600, habrá que hacer algo para aprovecharlas, ¿no? (al final me lío la manta a la cabeza y cableo el bloque a los vecinos, sino al tiempo). Pues aquí es donde entra en juego el balanceo de carga y el failover

Un poco de teoría

Empecemos por lo más sencillo, el failover: básicamente se trata de seleccionar una ruta alternativa de salida a internet, cuando la ruta principal falla. En mikoritk, si vamos al apartado IP -> Routes, veremos una lista de direcciones con una entrada especial que apunta a la dirección 0.0.0.0/0. Esta ruta es la ruta por defecto. Básicamente esa tabla representa una lista de caminos a tomar para resolver las distintas peticiones que llegan al router. Si la dirección ip que solicitamos no se puede resolver localmente, se encarrila por esa ruta por defecto, pidiendo a lo que sea que tengas por encima que te lleve hasta ello. Dichas rutas tienen distancias, que no es más que un orden por el cual vamos a consultarlas. En un router doméstico, las rutas locales (LAN) tienen distancia 0, mientras que la ruta por defecto, normalmente creada de forma dinámica por algun cliente dhcp o pppoe, tiene distancia 1. Eso hace que cuando pedimos una dirección local no nos mande a internet en busca de ella, sino que el propio router la resuelva internamente.
En mikrotik, montar un failover es la cosa más tonta del mundo: basta con añadir una segunda ruta (bien manualmente, bien automáticamente) con una distancia superior a la ruta por defecto. Así, si usamos un pincho 3G conectado al router por USB, veremos que el cliente dhcp que levanta el router sobre la interfaz LTE crea una ruta con distancia 2. Eso quieres decir que, mientras esté viva la ruta por defecto con distacia 1, no se usará nunca la ruta "alternativa", mientras que si muere la ruta por defecto con distancia = 1, se empezará a usar la siguiente disponible, en este caso la de la interfaz LTE con distancia = 2. Tan chorra como eso, no tiene más. Más adelante podréis ver esto en fotos, y cómo se comporta.
1613594043336.png


Ahora lo interesante, el balanceo de carga: entendemos por balanceo la distribución del tráfico entre dos o más interfaces de salida WAN. Esta distribución se puede hacer de muchas formas, pero este manual se va a centrar en la que creo es la forma más eficiente que tiene mikrotik de hacerlo, el balanceo de carga PCC (Per Connection Clasiffier). Tenéis otros dos métodos que podéis estuidar: uno muy facilito de entender (ECMP o Equal Cost Multi Path) y otro algo más complejo, aunque también interesante (NTH o de enésimo paquete). No obstante, nos vamos a centrar en PCC. Ahora bién, ¿cómo divide el tráfico PCC? Pues lo hace dividiendo la conexión por flujos o streams, de tal manera que, una vez establecida una conexión, esta permanezca en el mismo canuto de salida para todos los paquetes relacionados con ella. Esa clasificación por tipo de conexión se hace usando un algoritmo de hashing y un selector, para seleccionar (valga la rebuznancia) sobre qué aplicamos el hashing. El selector tiene varias opciones, pero usaremos "both-addresses" para clasificar el tráfico, de tal menera que la función hash trabajará con las direcciones de origen y destino que tiene en la cabecera de los paquetes IP y, una vez aplicada la función de hashing, tendremos un chorizo de 32 bits. Ese chorizo lo dividimos entre el número de WAN's que tengamos, y el resultado de la operación tendrá un resto. Ese resto será el indicador que usaremos para marcar el tráfico e indicarle por qué canuto tirar.

Por ejemplo, para una conexión con 2 WAN's y clasificación por "both-addresses" tendremos como divisor el número 2 y, como posibles resultados para el resto de la operación de división, el 0 y 1. Si el resto de la división es 0, marcaremos ese paquete para que tire por un canuto, y si es 1, por el otro. Esto se expresa en la opción correspondiente como PCC = both-addresses:2/0 para la primera conexión y PCC = both-addresses:2/1 para la segunda. (dividimos por dos las opciones de resto son 0 o 1). Para una conexión con 3 WANs, sería igual pero tendríamos tres posibles restos para dicha división, así que tendríamos una definición de both-addresses:3/0 para la primera conexión y PCC = both-addresses:3/1 para la segunda y PCC = both-addresses:3/2 para la tercera... y así sucesivamente, con todas las interfaces WAN que tengáis.

Manos a la obra

Doy por hecho que todos sabemos configurar una conexión en automático con el que sea nuestro operador. En mi caso tengo ether1 y ether2 conectados a o2 y Pepephone, respectivamente (acordaos de sacar ambas interfaces del bridge lan y de meter ambas en la lista WAN para que les aplique la regla general de masquerade). O2 trabaja con PPPoE para obtener IP pública, mientras que Pepephone trabaja con DHCP. Levantados sendos clientes en dichas interfaces, tendremos una tabla de rutas con dos entradas 0.0.0.0/0, una de ellas en azul, indicando que dicha entrada no está en uso. Lo primero que vamos a editar es uno de los dos clientes, bien el dhpc bien el pppoe, para indicarles que vamos a dar preferencia a una de las dos rutas, quedando la otra como failover. En mi caso, he decidido que Pepehone tiene preferencia y se queda con distancia = 1 en la ruta, mientras que el cliente PPPoE va a tener distancia = 2. Ya está, ya hemos acabado con el failover. Si no os lo creéis, abrid la consola, tirad un ping a google.com y, en mitad de la fiesta, tirad de uno de los dos cables, bien ether1 o ether2. Si tiráis de ether2, mi conexión preferida, veréis como ether1 entra en acción enseguida, y práctiamente no perdéis más que uno o dos paquetes. Dicha entrada con peso 2 ahora estará en negro, en lugar de en azúl. Si vuelve en sí la preferida, toma preferencia sobre la otra y vuelve a enrutar el tráfico por ella, pasando a estar en azul la que tiene distancia = 2. ¿fácil, no? Siguiente paso: mangle

Mangle es la herramienta que nos proporciona Mikrotik para el marcado de paquetes. La usaremos para clasificar y marcar el tráfico, de tal manera que lo podamos lanzar a una WAN u otra, según nos convenga. Lo primero que tenemos que saber es que mangle es incompatible con fasttrack. Ohh... qué pena. Así que, si queréis usar mangle, no queda otra que desprendernos de nuestra querida regla de fasttrack la cual nos hace volar en mikrotik. Pero, ¿a quien le importa? ¡vamos a tener dos líneas de 600 para usar ala vez!, por velocidad no va a ser. Una vez localizada la regla de fasttrack en ip -> firewall -> filter, la deshabilitamos y reiniciamos el equipo. Al hacerlo, veremos ques otras reglas de conteo de paquetes que aparecían en la parte superior del firewall, así como en el apartado mangle, desaparecen. No hay problema, son reglas dinámicas que se crean solitas al habilitar fasttrack. Si mañana queremos volver a usarlo, con habilitarlo y dar un reinicio al equipo, se crearán solas de nuevo. Una vez localizada la pestaña de mangle, al lío.

Lo primero que vamos a tratar son las excepciones. Hay veces en las que, por lo que quiera que sea, no nos interesa aplicar el balanceo sobre todo el tráfico, y necesitamos una regla para excepcionarlo. En mi caso, ese tráfico se llama VoIP, y lo tengo que excepcionar porque lleva su propia ruta dinámica (RIP) para telefónica movistar, y por tanto, idem para o2. La priemra regla que crearemos será la excepción de dicho tráfico. La regla dirá, si es tráfico de voz, acéptalo y pásalo al firewall, que es lo que se ejecuta justo después de mangle. En mi caso, dicha regla tiene este formato:
Código:
/ip firewall mangle
add action=accept chain=prerouting comment="bypass voip" dst-address=10.0.0.0/8 \
    in-interface=bridge
que quiere decir: todo lo que venga de mi lan interna, con destino la subred de la VoIP, y sobre el chain de prerouting, lo aceptas y se lo mandas al firewall, y que él decida qué hacer con ello.

A continuación, marcaremos las conexiones. Para ello, trabajaremos simpre sobre el chain de prerouting, y tenemos básicamente dos tipos de tráfico que marcar: el que viene desde fuera con destino dentro, y el que viene de la LAN con destino internet. Y os preguntaréis, ¿por qué narices tengo que marcar lo que viene de fuera, si a mi el balanceo me interesa sobre todo de salida: pues porque sino cabría la posibilidad de que respondieras a una conexión entrante por una IP pública que no fuera la que va como destino en la cabecera del paquete IP. El otro extremo diría, "Pero si yo he pedido hablar con Pepe, por qué me responde Juan" y ahí se acabó la converasación. Así que necestamos marcar ambos tipos de tráfico. Al lío:
Código:
add action=mark-connection chain=prerouting comment="mark connections" \
    connection-mark=no-mark in-interface=internet-pepephone \
    new-connection-mark=pepephone_conn passthrough=yes
add action=mark-connection chain=prerouting connection-mark=no-mark \
    in-interface=internet-o2 new-connection-mark=o2_conn passthrough=yes
add action=mark-connection chain=prerouting connection-mark=no-mark \
    dst-address-type=!local in-interface=bridge new-connection-mark=\
    pepephone_conn passthrough=yes per-connection-classifier=both-addresses:2/0
add action=mark-connection chain=prerouting connection-mark=no-mark \
    dst-address-type=!local in-interface=bridge new-connection-mark=o2_conn \
    passthrough=yes per-connection-classifier=both-addresses:2/1
En las primeras dos reglas estamos marcando la entrada: lo que venga por la interfaz pepephone y no tenga ya marca, le pones la marca de conexión "pepephone_conn", e idéntico para o2. En la segunda, marcamos el tráfico de nuestra LAN que no vaya con destino local, es decir, que salga a internet. Aquí entra en juego el PCC, clasificando la conexión en dos flujos o streams, atendiendo a las direcciones de origen y destino del paquete, como hemos explicado antes. La división obviamente no es perfecta, y puede que una interfaz reciba más tráfico que la otra, pero creedme cuando os digo que el método funciona muy muy bien y las conexiones están más o menos equilibradas.

Marcadas las conexiones, lo que nos queda es, es el empujoncito final: para dichas conexiones marcadas, aplicar una regla de routeo. Para ello, simplemente analizaremos las marcas de conexión y, a las que vengan con "pepephone_conn", las mandamos a la ruta que trabaje con la marca de routing "to_pepephone", y a la que venga con "o2_conn", la mandamos a otra ruta que trabaje sobre la marca de routing "to_o2". Cuando creamos marcas de routing, en verdad lo que estamos haciendo son nuevas tablas de routeo además de la tabla de routeo principal "main" (toda conexión no marcada con una marca de routing, va por defecto a la tabla "main"). Al igual que en el punto anterior, tendremos dos casuísiticas, esta vez relacionadas con distintos "chains": dos reglas para prerouting y dos para output. Las dos de prerouting se encargarán del tráfico que viene de la LAN ya clasificado. Las dos de output atenderán el tráfico que sale del propio router. Las reglas, serían estas:
Código:
add action=mark-routing chain=prerouting comment="mark routing" \
    connection-mark=pepephone_conn in-interface=bridge new-routing-mark=\
    to_pepephone passthrough=no
add action=mark-routing chain=prerouting connection-mark=o2_conn in-interface=\
    bridge new-routing-mark=to_o2 passthrough=no
add action=mark-routing chain=output connection-mark=pepephone_conn \
    new-routing-mark=to_pepephone passthrough=no
add action=mark-routing chain=output connection-mark=o2_conn new-routing-mark=\
    to_o2 passthrough=no
Como veis, muy simple: lo que venga con la marca de conexión X, al canuto X, lo que venga con Y, al Y... y así sucesivamente. Estas reglas tiene algo interesante, el "passthrough=no". Esa propiedad hace que el marcado de paquetes en esa cadena concreta termine ahí, y no se ejecuten las siguientes reglas. Total, si ya tenemos claro donde va un paquete de pepehone, para qué hacerle pasar por el análisis de marcado de o2. Así ahorramos ciclos de CPU.

Por último, y ya que estamos usando mangle y que nuestro operador nos define una prioridad para los servicios, marcamos dicha prioridad. Esto no es obligatorio, pero como o2 lo hace en su definición de interfaces, pues nosotros lo vamos a hacer igual. En mi caso, sólo internet y tfno. Si tuvierais tv, tres cuartos de lo mismo:
Código:
add action=set-priority chain=postrouting comment="vlan priority" new-priority=1 \
    out-interface=internet-o2 passthrough=no
add action=set-priority chain=postrouting new-priority=4 out-interface=\
    vlan-voip-o2 passthrough=no
El resultado final de la operación, sería tener algo como esto en mangle (obviad los nombres de mis interfaces)
1613594137431.png


Con esto y un bizcocho, hemos terminado con el mangle. Pasamos a configurar las rutas. Para las rutas, lo único que tenemos que hacer es definir dos nuevas rutas, específicas para las marcas de routeo que hemos hecho. Esas rutas serán las que de verdad trabajen, mientras ambas conexiones estén vivas y balanceando. Las rutas por defecto se quedarán de backup, para el tráfico sin marcar o para cuando algo falle en nuestra configuración. Pasamos a crear las dos rutas nuevas, una para el tráfico marcado como "to_pepephone" y otra para el tráfico marcado como "to_o2", ambas con una sonda de tipo "ping" para comprobar que siguen vivas:
Código:
/ip route
add check-gateway=ping comment=pp-load-balanced distance=1 gateway=212.231.184.1 \
    routing-mark=to_pepephone
add check-gateway=ping comment=o2-load-balanced distance=1 gateway=internet-o2 \
    routing-mark=to_o2
Como véis, hay una ligera diferencia entre ambas rutas. Mientras que en la ruta de pepephone especificamos la dirección concreta del gateway (la tenemos que extraer del detalle de conexión del cliente dhcp), la ruta de o2 es más simple y sólo neceista la propia interfaz como gateway. Esto es así por el tipo de conexión: mientras que una es un túnel punto a punto y te puedes permitir el lujo de decir "me da igual el gateway, tu tira el tráfico a la interfaz, que ella sabrá qué hacer con él en el otro extremo del túnel", en la otra has de especificar a quién se lo mandas. Podemos estar tentados de omitir este detalle y configurar la primera ruta con gateway=internet-pepehone, y de hecho funciona, pero creedme que no queréis hacerlo. Yo tuve la curiosidad, y se me quitó de golpe al ver que mi tabla ARP se llenaba de direcciones de internet públicas... decenas, centenares de ellas. Esto es así porque básicaemente lo que estás diciendo es "tú tíralo ahí, que ya sabrá el otro extremo qué hacer con ello" y claro, el otro extremo es un operador de internet, con decenas de servicios y servidores corriendo, los cuales vas a tener que ir descubriendo usando el protocolo ARP, de ahí que se llene la tabla. Al no ser una conexión punto a punto, no te puedes permitir ese lujo, una de las cosas buenas que tiene PPPoE. Pero bueno, como se suele decir, nunca te acostarás sin saber una cosa más... así que, niños, no intentéis esto en casa. Especialmente porque tus direcciones locales, las MAC e IP's de tus equipos de red local, se filtrarána tu operador. Y, afortunadamente, los routers de borde tienene una cosa llamada proxy-arp confiugrada, sino directamente es muy probable que incluso nos desconectasen de la red hasta que corrijamos el problema (no sería el primero ni el último al que le pasa). Así que ya sabéis, gateway=interfaz, caca, para conexiones DHCP. Las rutas, quedarían así, una vez creadas las dos nuevas entradas manuales para las marcas de routeo específicas:
1613594303536.png


Llegados a este punto ya tenemos todo el tinglado montado y funcionando. Si lo hemos hecho bien, en la tabla de rutas habrá cuatro entradas (si tenéis dos WANs) con la 0.0.0.0/0 como dirección de destino y el tráfico empezará a fluir balanceado. Y la pregunta creo que es obvia: "claro cachondo, pero si tenemos direcciones IP dinámicas en la mayoría de los casos, qué pasa cuando la IP cambia, ¿eh?" Pues habéis intuido bien, el tinglado se nos va al garete. La ruta dinámica sobrevibe, puesto que como su propio nombre indica es dinámica, y cambiará cuando el cliente dhcp obtenga una nueva dirección IP, así como su correspondiente gateway. Pero la que hemos dado de alta a mano se nos fastidia, así que necesitamos corregir eso. Para hacerlo, lo que vamos a montar es un script que añadiremos al cliente DHCP, tal que sea capaz de modificar esa que hemos dado de alta a mano, automáticamente. El script está sacado de la wiki de mikrotik, y adaptado a mis necesidades.
Lo primero que tenemos que hacer es etiquetar la ruta problemática, la de pepehone, con un comentario cualquiera, en mi caso "pp-load-balanced", tal que seamos capaces de leerla en el script. Una vez hecho, iremos a IP -> dhcp-client y editaremos el cliente dhcp asocidado a nuestra conexión DHCP, en mi caso "internet-pepephone", y le meteremos el siguiente script en la pestaña "Advanced"
1613595047570.png

Código:
{
    :local rmark "to_pepephone"
    :local rcomment "pp-load-balanced"
    :local rcount [/ip route print count-only where comment=$rcomment]
    :if ($bound=1) do={
        :if ($rcount = 0) do={
            /ip route add gateway=$"gateway-address" comment=$rcomment routing-mark=$rmark check-gateway=ping
        } else={
            :if ($rcount = 1) do={
                :local test [/ip route find where comment=$rcomment]
                :if ([/ip route get $test gateway] != $"gateway-address") do={
                    /ip route set $test gateway=$"gateway-address"
                }
            } else={
                :error "Multiple routes found with the same comment!"
            }
        }
    } else={
        /ip route remove [find comment=$rcomment]
    }
}
El script parece complejo, pero es una chorrada. Define tres variables, la marca de ruta que vamos a aplicar (rmark), el comentario que estamos buscando en la ruta (rcomment) y el número de veces que encuentra ese comentario sobre una ruta en la tabla de rutas (rcount), esto último, para cuando la ruta ya existe. Si la ruta no existe se crea y si existe, se testea si el gateway que lleva al ruta coincide o no con el del cliente dhcp. Si no coincide, actualizamos la ruta. Y, si encontramos más de una ruta con el mismo comentario, algo tenemos mal, así que metemos una línea en el log, de las que salen en rojo.
Si el cliente dhcp falla a la hora de obtener una dirección IP (ejemplo cuando se nos corta internet por un fallo del operador y el cliente dhcp se nos va a la mierda), borramos la ruta estática (ya no tanto) que lleva el tráfico a ese operador. Al borrarse de la tabla de rutas, la regla de mangle que etiqueta el tráfico de entrada por esa interfaz deja de funcionar y, aunque la de salida del PCC sigue funcionando, al no encontrar una ruta específica para esa etiqueta en la tabla de rutas, lo tirará por la tabla "main", para la que sea la ruta que esté actuando por defecto. Resultado: ni nos enteramos de que se nos ha caido internet, porque todo sigue funcionando.
Puede darse el caso de que el cliente DHCP no falle, aún, porque el lease time aguante hasta que le toque renovar la conexión DHCP, pero que el gateway no responda: para ese caso está el "check-gateway=ping" en la ruta, el cual comprobará cada 10s que tu gateway sigue vivo. A los dos timeouts, dará de baja esa ruta y la marcará como no disponible.

Conclusión

¿Merece la pena? Pues sinceramente, creo que no. Dado que las velocidades que manejamos hoy en día en casa son tan absurdamente altas, no creo que aproveche jamás el beneficio que me brinda el balanceo de carga con dos conexiones simétricas de 600. Pero es una cosa que tenía pendiente probar y... ya que estamos, manual al canto. Eso, y que me jode mucho tener un chisme enchufado haciendo nada, así que o2, te toca pringar también. No obstante, creo que puede ser una guía muy útil para quien tenga la posibilidad de montar un par de líneas o tres y distribuir el servicio entre muchos, como por ejemplo, una comunidad de vecinos que se lleve bien.

Con esto y otro bizcocho... balanceo de carga PCC con failover; que Uds lo disfruten.

Saludos!
 
Impresionante manual!! Enhorabuena y muchas gracias, @pocoyo.

Me apunto para catarlo, en mi caso probaré la configuración de failover con una conexión ftth como principal y una conexión con router 4G de "backup"

Increíble lo que pueden dar de sí estos aparatos. Por cierto, una vez configuras los servicios de failover y balanceo, ¿se nota mucho el consumo de recursos en el MK?.


Saludos!!
 
Impresionante manual!! Enhorabuena y muchas gracias, @pocoyo.

Me apunto para catarlo, en mi caso probaré la configuración de failover con una conexión ftth como principal y una conexión con router 4G de "backup"

Increíble lo que pueden dar de sí estos aparatos. Por cierto, una vez configuras los servicios de failover y balanceo, ¿se nota mucho el consumo de recursos en el MK?.


Saludos!!
Gracias, me alegro de que te guste.

Pues todo depende del equipo, claro está, y de la cantidad de tráfico que esté moviendo. Perder el fasttrack es una putada, pero no te queda más remedio si quieres que mangle funcione.

Se nota cuando metes 10 torrents a descargar y fuerzas un cerro de conexiones, tal que hagas trabajar a las dos líneas a la vez y fuerces el bridge al límite de lo que da de sí la interfaz (1Gbps en mi caso). Pero sinceramente, no he conseguido sacarle provecho aún.
Lo que sí me da es tranquilidad, sabiendo que es muy raro que me falle internet.

Si sólo lo quieres con failover, ya ves que es muy sencillito, basta con levantar la otra interfaz con distancia = 2. De hecho, lo hace solito el router cuando pones a funcionar la conexión usb para una interfaz LTE, por ejemplo.

Saludos!
 
Muy buenas @pocoyo,

Sí, en mi caso, el tema de balanceo, más que ayudarme...creo que ralentizaría mi conexión, por la diferencia de velocidad y latencia entre una conexión FTTH y una 4G (a diferencia de tu caso, que trabajas con dos canales de fibra), de ahí que utilizaría la opción de failover, para si el día de mañana falla la fibra, "salte" automáticamente la conexión 4G.

La opción de fasttrack solo se pierde al activar el balanceo, ¿es así? Si activo únicamente failover, puede seguir activada.

Muchas gracias!!
 
Muy buenas @pocoyo,

Sí, en mi caso, el tema de balanceo, más que ayudarme...creo que ralentizaría mi conexión, por la diferencia de velocidad y latencia entre una conexión FTTH y una 4G (a diferencia de tu caso, que trabajas con dos canales de fibra), de ahí que utilizaría la opción de failover, para si el día de mañana falla la fibra, "salte" automáticamente la conexión 4G.

La opción de fasttrack solo se pierde al activar el balanceo, ¿es así? Si activo únicamente failover, puede seguir activada.

Muchas gracias!!
Correcto. Para el balanceo no tocas mangle, así que no es necesario quitar fasttrack. Y la configuración del failover, como ves, es una chorrada.

Saludos!
 

Introducción

Hoy vamos a hablar de un tema la mar de interesante, si bien no es demasiado usado a nivel doméstico. Se trata del balanceo de carga con failover. Básicamente cómo aprovechar tu conexión, cuando tienes dos líneas de internet.

Propósito

El propósito de este manual viene de una nueva necesidad: trabajo de normal desde casa y llevaba tiempo con el runrun de poner una segunda conexión a internet. Normalmente, cuando fallaba mi querido Pepephone (todas fallan alguna vez), tiraba de la conexión móvil. Pero, dado que vivo en una zona con escasa cobertura, cumplir con mi trabajo se me hacía complicado usando este tipo de conexión. Esto, unido a que derivado de la pandemia la situación en casa ha cambiado y ya no soy yo sólo el que trabaja en remoto, me hizo plantearme que no sería nada descabellado tener una segunda conexión a internet (dos fibras) por si, $deity no lo quiera, mi querido Pepephone me dejaba tirado en algún momento. Estudiadas las ofertas y haciendo números, opté por contratar con o2, de la cual ya tenía buenas referencias por un par de instalaciones en casa de familiares. Además de esto, en mi casa ya existía una toma de fibra de telefónica, que Pepephone respetó cuando instaló la suya, así que supuse que iba a ser coser y cantar. Dicho y hecho, el móvil costó un poco más, pero la fibra estaba instalada al día siguiente de pedirla. Y ahora viene cuando pokoyo se pregunta, ¿qué coj_nes hago yo con dos líneas de 600, cómo las aprovecho? Porque, si ya me parecía burra la de 300 simétricos, ahora con dos de 600, habrá que hacer algo para aprovecharlas, ¿no? (al final me lío la manta a la cabeza y cableo el bloque a los vecinos, sino al tiempo). Pues aquí es donde entra en juego el balanceo de carga y el failover

Un poco de teoría

Empecemos por lo más sencillo, el failover: básicamente se trata de seleccionar una ruta alternativa de salida a internet, cuando la ruta principal falla. En mikoritk, si vamos al apartado IP -> Routes, veremos una lista de direcciones con una entrada especial que apunta a la dirección 0.0.0.0/0. Esta ruta es la ruta por defecto. Básicamente esa tabla representa una lista de caminos a tomar para resolver las distintas peticiones que llegan al router. Si la dirección ip que solicitamos no se puede resolver localmente, se encarrila por esa ruta por defecto, pidiendo a lo que sea que tengas por encima que te lleve hasta ello. Dichas rutas tienen distancias, que no es más que un orden por el cual vamos a consultarlas. En un router doméstico, las rutas locales (LAN) tienen distancia 0, mientras que la ruta por defecto, normalmente creada de forma dinámica por algun cliente dhcp o pppoe, tiene distancia 1. Eso hace que cuando pedimos una dirección local no nos mande a internet en busca de ella, sino que el propio router la resuelva internamente.
En mikrotik, montar un failover es la cosa más tonta del mundo: basta con añadir una segunda ruta (bien manualmente, bien automáticamente) con una distancia superior a la ruta por defecto. Así, si usamos un pincho 3G conectado al router por USB, veremos que el cliente dhcp que levanta el router sobre la interfaz LTE crea una ruta con distancia 2. Eso quieres decir que, mientras esté viva la ruta por defecto con distacia 1, no se usará nunca la ruta "alternativa", mientras que si muere la ruta por defecto con distancia = 1, se empezará a usar la siguiente disponible, en este caso la de la interfaz LTE con distancia = 2. Tan chorra como eso, no tiene más. Más adelante podréis ver esto en fotos, y cómo se comporta.
Ver el adjunto 78937

Ahora lo interesante, el balanceo de carga: entendemos por balanceo la distribución del tráfico entre dos o más interfaces de salida WAN. Esta distribución se puede hacer de muchas formas, pero este manual se va a centrar en la que creo es la forma más eficiente que tiene mikrotik de hacerlo, el balanceo de carga PCC (Per Connection Clasiffier). Tenéis otros dos métodos que podéis estuidar: uno muy facilito de entender (ECMP o Equal Cost Multi Path) y otro algo más complejo, aunque también interesante (NTH o de enésimo paquete). No obstante, nos vamos a centrar en PCC. Ahora bién, ¿cómo divide el tráfico PCC? Pues lo hace dividiendo la conexión por flujos o streams, de tal manera que, una vez establecida una conexión, esta permanezca en el mismo canuto de salida para todos los paquetes relacionados con ella. Esa clasificación por tipo de conexión se hace usando un algoritmo de hashing y un selector, para seleccionar (valga la rebuznancia) sobre qué aplicamos el hashing. El selector tiene varias opciones, pero usaremos "both-addresses" para clasificar el tráfico, de tal menera que la función hash trabajará con las direcciones de origen y destino que tiene en la cabecera de los paquetes IP y, una vez aplicada la función de hashing, tendremos un chorizo de 32 bits. Ese chorizo lo dividimos entre el número de WAN's que tengamos, y el resultado de la operación tendrá un resto. Ese resto será el indicador que usaremos para marcar el tráfico e indicarle por qué canuto tirar.

Por ejemplo, para una conexión con 2 WAN's y clasificación por "both-addresses" tendremos como divisor el número 2 y, como posibles resultados para el resto de la operación de división, el 0 y 1. Si el resto de la división es 0, marcaremos ese paquete para que tire por un canuto, y si es 1, por el otro. Esto se expresa en la opción correspondiente como PCC = both-addresses:2/0 para la primera conexión y PCC = both-addresses:2/1 para la segunda. (dividimos por dos las opciones de resto son 0 o 1). Para una conexión con 3 WANs, sería igual pero tendríamos tres posibles restos para dicha división, así que tendríamos una definición de both-addresses:3/0 para la primera conexión y PCC = both-addresses:3/1 para la segunda y PCC = both-addresses:3/2 para la tercera... y así sucesivamente, con todas las interfaces WAN que tengáis.

Manos a la obra

Doy por hecho que todos sabemos configurar una conexión en automático con el que sea nuestro operador. En mi caso tengo ether1 y ether2 conectados a o2 y Pepephone, respectivamente (acordaos de sacar ambas interfaces del bridge lan y de meter ambas en la lista WAN para que les aplique la regla general de masquerade). O2 trabaja con PPPoE para obtener IP pública, mientras que Pepephone trabaja con DHCP. Levantados sendos clientes en dichas interfaces, tendremos una tabla de rutas con dos entradas 0.0.0.0/0, una de ellas en azul, indicando que dicha entrada no está en uso. Lo primero que vamos a editar es uno de los dos clientes, bien el dhpc bien el pppoe, para indicarles que vamos a dar preferencia a una de las dos rutas, quedando la otra como failover. En mi caso, he decidido que Pepehone tiene preferencia y se queda con distancia = 1 en la ruta, mientras que el cliente PPPoE va a tener distancia = 2. Ya está, ya hemos acabado con el failover. Si no os lo creéis, abrid la consola, tirad un ping a google.com y, en mitad de la fiesta, tirad de uno de los dos cables, bien ether1 o ether2. Si tiráis de ether2, mi conexión preferida, veréis como ether1 entra en acción enseguida, y práctiamente no perdéis más que uno o dos paquetes. Dicha entrada con peso 2 ahora estará en negro, en lugar de en azúl. Si vuelve en sí la preferida, toma preferencia sobre la otra y vuelve a enrutar el tráfico por ella, pasando a estar en azul la que tiene distancia = 2. ¿fácil, no? Siguiente paso: mangle

Mangle es la herramienta que nos proporciona Mikrotik para el marcado de paquetes. La usaremos para clasificar y marcar el tráfico, de tal manera que lo podamos lanzar a una WAN u otra, según nos convenga. Lo primero que tenemos que saber es que mangle es incompatible con fasttrack. Ohh... qué pena. Así que, si queréis usar mangle, no queda otra que desprendernos de nuestra querida regla de fasttrack la cual nos hace volar en mikrotik. Pero, ¿a quien le importa? ¡vamos a tener dos líneas de 600 para usar ala vez!, por velocidad no va a ser. Una vez localizada la regla de fasttrack en ip -> firewall -> filter, la deshabilitamos y reiniciamos el equipo. Al hacerlo, veremos ques otras reglas de conteo de paquetes que aparecían en la parte superior del firewall, así como en el apartado mangle, desaparecen. No hay problema, son reglas dinámicas que se crean solitas al habilitar fasttrack. Si mañana queremos volver a usarlo, con habilitarlo y dar un reinicio al equipo, se crearán solas de nuevo. Una vez localizada la pestaña de mangle, al lío.

Lo primero que vamos a tratar son las excepciones. Hay veces en las que, por lo que quiera que sea, no nos interesa aplicar el balanceo sobre todo el tráfico, y necesitamos una regla para excepcionarlo. En mi caso, ese tráfico se llama VoIP, y lo tengo que excepcionar porque lleva su propia ruta dinámica (RIP) para telefónica movistar, y por tanto, idem para o2. La priemra regla que crearemos será la excepción de dicho tráfico. La regla dirá, si es tráfico de voz, acéptalo y pásalo al firewall, que es lo que se ejecuta justo después de mangle. En mi caso, dicha regla tiene este formato:
Código:
/ip firewall mangle
add action=accept chain=prerouting comment="bypass voip" dst-address=10.0.0.0/8 \
in-interface=bridge
que quiere decir: todo lo que venga de mi lan interna, con destino la subred de la VoIP, y sobre el chain de prerouting, lo aceptas y se lo mandas al firewall, y que él decida qué hacer con ello.

A continuación, marcaremos las conexiones. Para ello, trabajaremos simpre sobre el chain de prerouting, y tenemos básicamente dos tipos de tráfico que marcar: el que viene desde fuera con destino dentro, y el que viene de la LAN con destino internet. Y os preguntaréis, ¿por qué narices tengo que marcar lo que viene de fuera, si a mi el balanceo me interesa sobre todo de salida: pues porque sino cabría la posibilidad de que respondieras a una conexión entrante por una IP pública que no fuera la que va como destino en la cabecera del paquete IP. El otro extremo diría, "Pero si yo he pedido hablar con Pepe, por qué me responde Juan" y ahí se acabó la converasación. Así que necestamos marcar ambos tipos de tráfico. Al lío:
Código:
add action=mark-connection chain=prerouting comment="mark connections" \
connection-mark=no-mark in-interface=internet-pepephone \
new-connection-mark=pepephone_conn passthrough=yes
add action=mark-connection chain=prerouting connection-mark=no-mark \
in-interface=internet-o2 new-connection-mark=o2_conn passthrough=yes
add action=mark-connection chain=prerouting connection-mark=no-mark \
dst-address-type=!local in-interface=bridge new-connection-mark=\
pepephone_conn passthrough=yes per-connection-classifier=both-addresses:2/0
add action=mark-connection chain=prerouting connection-mark=no-mark \
dst-address-type=!local in-interface=bridge new-connection-mark=o2_conn \
passthrough=yes per-connection-classifier=both-addresses:2/1
En las primeras dos reglas estamos marcando la entrada: lo que venga por la interfaz pepephone y no tenga ya marca, le pones la marca de conexión "pepephone_conn", e idéntico para o2. En la segunda, marcamos el tráfico de nuestra LAN que no vaya con destino local, es decir, que salga a internet. Aquí entra en juego el PCC, clasificando la conexión en dos flujos o streams, atendiendo a las direcciones de origen y destino del paquete, como hemos explicado antes. La división obviamente no es perfecta, y puede que una interfaz reciba más tráfico que la otra, pero creedme cuando os digo que el método funciona muy muy bien y las conexiones están más o menos equilibradas.

Marcadas las conexiones, lo que nos queda es, es el empujoncito final: para dichas conexiones marcadas, aplicar una regla de routeo. Para ello, simplemente analizaremos las marcas de conexión y, a las que vengan con "pepephone_conn", las mandamos a la ruta que trabaje con la marca de routing "to_pepephone", y a la que venga con "o2_conn", la mandamos a otra ruta que trabaje sobre la marca de routing "to_o2". Cuando creamos marcas de routing, en verdad lo que estamos haciendo son nuevas tablas de routeo además de la tabla de routeo principal "main" (toda conexión no marcada con una marca de routing, va por defecto a la tabla "main"). Al igual que en el punto anterior, tendremos dos casuísiticas, esta vez relacionadas con distintos "chains": dos reglas para prerouting y dos para output. Las dos de prerouting se encargarán del tráfico que viene de la LAN ya clasificado. Las dos de output atenderán el tráfico que sale del propio router. Las reglas, serían estas:
Código:
add action=mark-routing chain=prerouting comment="mark routing" \
connection-mark=pepephone_conn in-interface=bridge new-routing-mark=\
to_pepephone passthrough=no
add action=mark-routing chain=prerouting connection-mark=o2_conn in-interface=\
bridge new-routing-mark=to_o2 passthrough=no
add action=mark-routing chain=output connection-mark=pepephone_conn \
new-routing-mark=to_pepephone passthrough=no
add action=mark-routing chain=output connection-mark=o2_conn new-routing-mark=\
to_o2 passthrough=no
Como veis, muy simple: lo que venga con la marca de conexión X, al canuto X, lo que venga con Y, al Y... y así sucesivamente. Estas reglas tiene algo interesante, el "passthrough=no". Esa propiedad hace que el marcado de paquetes en esa cadena concreta termine ahí, y no se ejecuten las siguientes reglas. Total, si ya tenemos claro donde va un paquete de pepehone, para qué hacerle pasar por el análisis de marcado de o2. Así ahorramos ciclos de CPU.

Por último, y ya que estamos usando mangle y que nuestro operador nos define una prioridad para los servicios, marcamos dicha prioridad. Esto no es obligatorio, pero como o2 lo hace en su definición de interfaces, pues nosotros lo vamos a hacer igual. En mi caso, sólo internet y tfno. Si tuvierais tv, tres cuartos de lo mismo:
Código:
add action=set-priority chain=postrouting comment="vlan priority" new-priority=1 \
out-interface=internet-o2 passthrough=no
add action=set-priority chain=postrouting new-priority=4 out-interface=\
vlan-voip-o2 passthrough=no
El resultado final de la operación, sería tener algo como esto en mangle (obviad los nombres de mis interfaces)
Ver el adjunto 78940

Con esto y un bizcocho, hemos terminado con el mangle. Pasamos a configurar las rutas. Para las rutas, lo único que tenemos que hacer es definir dos nuevas rutas, específicas para las marcas de routeo que hemos hecho. Esas rutas serán las que de verdad trabajen, mientras ambas conexiones estén vivas y balanceando. Las rutas por defecto se quedarán de backup, para el tráfico sin marcar o para cuando algo falle en nuestra configuración. Pasamos a crear las dos rutas nuevas, una para el tráfico marcado como "to_pepephone" y otra para el tráfico marcado como "to_o2", ambas con una sonda de tipo "ping" para comprobar que siguen vivas:
Código:
/ip route
add check-gateway=ping comment=pp-load-balanced distance=1 gateway=212.231.184.1 \
routing-mark=to_pepephone
add check-gateway=ping comment=o2-load-balanced distance=1 gateway=internet-o2 \
routing-mark=to_o2
Como véis, hay una ligera diferencia entre ambas rutas. Mientras que en la ruta de pepephone especificamos la dirección concreta del gateway (la tenemos que extraer del detalle de conexión del cliente dhcp), la ruta de o2 es más simple y sólo neceista la propia interfaz como gateway. Esto es así por el tipo de conexión: mientras que una es un túnel punto a punto y te puedes permitir el lujo de decir "me da igual el gateway, tu tira el tráfico a la interfaz, que ella sabrá qué hacer con él en el otro extremo del túnel", en la otra has de especificar a quién se lo mandas. Podemos estar tentados de omitir este detalle y configurar la primera ruta con gateway=internet-pepehone, y de hecho funciona, pero creedme que no queréis hacerlo. Yo tuve la curiosidad, y se me quitó de golpe al ver que mi tabla ARP se llenaba de direcciones de internet públicas... decenas, centenares de ellas. Esto es así porque básicaemente lo que estás diciendo es "tú tíralo ahí, que ya sabrá el otro extremo qué hacer con ello" y claro, el otro extremo es un operador de internet, con decenas de servicios y servidores corriendo, los cuales vas a tener que ir descubriendo usando el protocolo ARP, de ahí que se llene la tabla. Al no ser una conexión punto a punto, no te puedes permitir ese lujo, una de las cosas buenas que tiene PPPoE. Pero bueno, como se suele decir, nunca te acostarás sin saber una cosa más... así que, niños, no intentéis esto en casa. Especialmente porque tus direcciones locales, las MAC e IP's de tus equipos de red local, se filtrarána tu operador. Y, afortunadamente, los routers de borde tienene una cosa llamada proxy-arp confiugrada, sino directamente es muy probable que incluso nos desconectasen de la red hasta que corrijamos el problema (no sería el primero ni el último al que le pasa). Así que ya sabéis, gateway=interfaz, caca, para conexiones DHCP. Las rutas, quedarían así, una vez creadas las dos nuevas entradas manuales para las marcas de routeo específicas:
Ver el adjunto 78943

Llegados a este punto ya tenemos todo el tinglado montado y funcionando. Si lo hemos hecho bien, en la tabla de rutas habrá cuatro entradas (si tenéis dos WANs) con la 0.0.0.0/0 como dirección de destino y el tráfico empezará a fluir balanceado. Y la pregunta creo que es obvia: "claro cachondo, pero si tenemos direcciones IP dinámicas en la mayoría de los casos, qué pasa cuando la IP cambia, ¿eh?" Pues habéis intuido bien, el tinglado se nos va al garete. La ruta dinámica sobrevibe, puesto que como su propio nombre indica es dinámica, y cambiará cuando el cliente dhcp obtenga una nueva dirección IP, así como su correspondiente gateway. Pero la que hemos dado de alta a mano se nos fastidia, así que necesitamos corregir eso. Para hacerlo, lo que vamos a montar es un script que añadiremos al cliente DHCP, tal que sea capaz de modificar esa que hemos dado de alta a mano, automáticamente. El script está sacado de la wiki de mikrotik, y adaptado a mis necesidades.
Lo primero que tenemos que hacer es etiquetar la ruta problemática, la de pepehone, con un comentario cualquiera, en mi caso "pp-load-balanced", tal que seamos capaces de leerla en el script. Una vez hecho, iremos a IP -> dhcp-client y editaremos el cliente dhcp asocidado a nuestra conexión DHCP, en mi caso "internet-pepephone", y le meteremos el siguiente script en la pestaña "Advanced"
Ver el adjunto 78946
Código:
{
:local rmark "to_pepephone"
:local rcomment "pp-load-balanced"
:local rcount [/ip route print count-only where comment=$rcomment]
:if ($bound=1) do={
:if ($rcount = 0) do={
/ip route add gateway=$"gateway-address" comment=$rcomment routing-mark=$rmark check-gateway=ping
} else={
:if ($rcount = 1) do={
:local test [/ip route find where comment=$rcomment]
:if ([/ip route get $test gateway] != $"gateway-address") do={
/ip route set $test gateway=$"gateway-address"
}
} else={
:error "Multiple routes found with the same comment!"
}
}
} else={
/ip route remove [find comment=$rcomment]
}
}
El script parece complejo, pero es una chorrada. Define tres variables, la marca de ruta que vamos a aplicar (rmark), el comentario que estamos buscando en la ruta (rcomment) y el número de veces que encuentra ese comentario sobre una ruta en la tabla de rutas (rcount), esto último, para cuando la ruta ya existe. Si la ruta no existe se crea y si existe, se testea si el gateway que lleva al ruta coincide o no con el del cliente dhcp. Si no coincide, actualizamos la ruta. Y, si encontramos más de una ruta con el mismo comentario, algo tenemos mal, así que metemos una línea en el log, de las que salen en rojo.
Si el cliente dhcp falla a la hora de obtener una dirección IP (ejemplo cuando se nos corta internet por un fallo del operador y el cliente dhcp se nos va a la mierda), borramos la ruta estática (ya no tanto) que lleva el tráfico a ese operador. Al borrarse de la tabla de rutas, la regla de mangle que etiqueta el tráfico de entrada por esa interfaz deja de funcionar y, aunque la de salida del PCC sigue funcionando, al no encontrar una ruta específica para esa etiqueta en la tabla de rutas, lo tirará por la tabla "main", para la que sea la ruta que esté actuando por defecto. Resultado: ni nos enteramos de que se nos ha caido internet, porque todo sigue funcionando.
Puede darse el caso de que el cliente DHCP no falle, aún, porque el lease time aguante hasta que le toque renovar la conexión DHCP, pero que el gateway no responda: para ese caso está el "check-gateway=ping" en la ruta, el cual comprobará cada 10s que tu gateway sigue vivo. A los dos timeouts, dará de baja esa ruta y la marcará como no disponible.

Conclusión

¿Merece la pena? Pues sinceramente, creo que no. Dado que las velocidades que manejamos hoy en día en casa son tan absurdamente altas, no creo que aproveche jamás el beneficio que me brinda el balanceo de carga con dos conexiones simétricas de 600. Pero es una cosa que tenía pendiente probar y... ya que estamos, manual al canto. Eso, y que me jode mucho tener un chisme enchufado haciendo nada, así que o2, te toca pringar también. No obstante, creo que puede ser una guía muy útil para quien tenga la posibilidad de montar un par de líneas o tres y distribuir el servicio entre muchos, como por ejemplo, una comunidad de vecinos que se lleve bien.

Con esto y otro bizcocho... balanceo de carga PCC con failover; que Uds lo disfruten.

Saludos!

Como siempre, @pokoyo de 10!!! Gracias
 
Me vas a hacer probarlo con un pincho USB que tengo...... Muchas gracias.

Enviado desde mi Mi 9T Pro mediante Tapatalk
 
Me vas a hacer probarlo con un pincho USB que tengo...... Muchas gracias.

Enviado desde mi Mi 9T Pro mediante Tapatalk
Pero con el pincho no hagas balanceo, haz solo la parte del failover. Que sino, vas a tostar los megas de la conexión móvil.

Saludos!
 
Chapeau, compañero! Otro manual genial, más. Gracias por el esfuerzo, pero como bien dices, me temo que, salvo en oficinas o comunidades de vecinos, no le vamos a poder sacar partido. Y es que estamos obsesionados con la “velocidad”, como en los coches: Una cosa es que podamos subir o bajar ficheros en, ¿la mitad, un tercio del tiempo que empleamos a 300mbs? Vale. Pero otra muy distinta es el Caudal Medio que estemos demandado a lo largo del día. Y en una casa normal, ya te digo que hasta con 100mbp puedes tener bastante. Pero no te quiero quitar mérito por el esfuerzo didáctico: al contrario. Enhorabuena.

De hecho, me has metido con esto el run run en la cabeza de si podriamos encontrar una alternativa al problema multidesco en Movistar basado en dos rutas en vez del script de Toniros. Esta claro que es tema de otro hilo, pero, simplemente, decirte que ya probé en su día marcar con mangle la conexion cuando se inicia una orden VOD por RTSP y después aplicar la regla dstnat al desco basado en ese marcaje, pero no funciona, porque sno conexiones distintas, la de la orden inicial y la del flujo RTSP. Lo que estaba pensando es, al detectar una orden VOD de un desco, marcar en vez una ruta, y tener dos reglas dstnat, una para cada desco, una por cada ruta. ¿Crees que es solo una idea feliz inspirada por esta estupenda lección, o podría ser una camino para solventar el RTSP ALG sin tener un script corriendo todo el rato?

muchas gracias!
 
Me respondo a mi mismo: creo que no es posible. La única forma de discernir entre dos flujos RTSP distintos, dirigidos a descos distintos, es yendo a analizarlos al N7, si no queremos ir eliminando y cambiando la regla dstnat. El problema es que la conexión con el flujo dstnat entra como una nueva conexión desde el servidor VOD, y la relación con la orden que la generó se distingue a nivel 7, o bien como propuso Toniros: detectando el desco que la origina y creando una regla a capón enchufándole todo el tráfico entrante a ese desco. Pero es que desde la conexión entrante, no podemos poner ningún "match" en la regla dstnat que la relacione con la orden generadora, salvo esas dos formas, me temo, y por ello, no podemos poner sendas reglas dstnat para cada desco, que nos permitiera prescindir del script de creación y eliminación. Disculpas por "ensuciar" este hilo.
 
Nada, descuida que no ensucias. Ya le daremos una pensada, que no estoy yo muy puesto en el tema de RSTP. Pero estoy seguro de que algo se puede hacer, identificando la conexión entrante y marcando esos paquetes.

Insisto, ya lo miraremos más tranquilos.

Saludos!
 
Genial, muchas gracias por el curro !!!
Está super-interesante el tema.
Otro más pa'encuadernar. Que lujo.
Saludos.
 
Arriba