100Mbps + 100Mbps = 200Mbps: port trunking (a.k.a. bonding ports)

networkingArco

Probablemente muchos de vosotros tengáis equipos con varias tarjetas de red, esto puede usarse para muchas cosas, una de ellas (a mi entender muy interesante) es el port trunking o también conocido como port bonding.

¿Qué es el port bonding?

Es una técnica que permite agregar varios interfaces de red físicos en uno único virtual. A cada interfaz físico se le denominará slave (esclavo). Con esto podemos realizar un balanceo de carga entre las dos interfaces y conseguir un ancho de banda final igual a la suma de los anchos de banda de cada slave. Además de una ventaja adicional inmediata: redundancia de la conexión. Tenemos varios enlaces físicos a la red, perder alguno de ellos implica una degradación de servicio pero no la pérdida completa de conexión.

Ingredientes

Es necesario un módulo que viene de serie incluído en los linux 2.4 y 2.6. Además también hace falta el programa que gestiona las interfaces: ifenslave, que viene empaquetado en Debian para disfrute de todos nosotros:

# aptitude install ifenslave-2.6

El módulo bonding

Para crear la interfaz virtual debemos cargar un módulo que la gestione aplicando alguna política o algoritmo para ello. Este módulo tiene muchos parámetros, aunque creo que antes de listarlos todos explicaremos un poco el funcionamiento teórico para entender mejor los parámetros.

Slaves y colas

Toda interfaz de red tiene asignada automáticamente una cola de envío y otra de recepción. Cada slave tiene también sus propias colas. El esquema es más o menos el siguiente (supondremos dos slaves):

RED ----> ETH0(RX) --->\
                        BOND0(RX) ----> S.O.
RED ----> ETH1(RX) --->/

                    /----> ETH0(TX) ----> RED
S.O. ----> BOND0(TX)
                    \----> ETH1(TX) ----> RED

(Ole ese ASCII ART!)
En cuanto a la recepción hay poco que decir, cuando llega un paquete
a algún slave se pasa a la cola de recepción de la interfaz virtual. Si un enlace físico falla, hay poco que podamos hacer: símplemente se degradará el servicio. Pero para el envío hay un poco más de historia, puesto que si detectamos que un enlace se ha perdido, deberemos pasar todos los paquetes de la cola de esa interfaz a la esclava que sigue funcionando para después congelar esa cola de envío degradando así el rendimiento de la interfaz. Por tanto debemos poder detectar cuando un enlace se ha caído, a este respecto existen dos posibilidades: detección por ARP o mediante MII (Media Indepent Interface).

  • Detección ARP: consiste en enviar periódicamente peticiones ARP por un slave, si estas peticiones fallan el enlace se considera caído.
  • Detección MII: si el módulo de la NIC (Network Interface Card) implementa ciertas llamadas, se puede detectar cuando un enlace está físicamente caído, en cuyo caso, se deshabilita el slave.

Evidentemente, los esclavos deshabilitados se seguirán probando hasta que vuelvan a estar operativos, momento en el cual se volverán a habilitar dentro de la interfaz virtual.

Balanceos de carga

Probablemente este sea el aspecto más importante del bonding: cómo balancear la carga entre todos los esclavos. En este sentido el módulo tiene un parámetro que permite indicar qué algoritmo se debe usar, los algoritmos implementados son:

  • balance-rr (modo 0): se emplea un algoritmo round robin entre la cola virtual y las de los esclavos. Es algo así como: un paquetillo para un esclavo, otro para otro esclavo, un paquetillo para un esclavo, otro para el otro... etc. Es el algoritmo que se usa por defecto.
  • active-backup (modo 1): realmente no balancea la carga, usa sólo un esclavo y en caso de fallar, usa el siguiente disponible.
  • balance-xor (modo 2): emplea una formulita para decidir por qué interfaz sale: (source-MAC xor dest-MAC) mod n-slaves.
  • broadcast (modo 3): se transmite todo por todas las interfaces. Este método no balancea tampoco, pero provee tolerancia a fallos.
  • 802.3ad (modo 4): emplea algoritmos definidos en el estándar IEEE 802.3ad.
  • balance-tlb (modo 5): balancea la carga de transmisión entre los esclavos dependiendo de la velocidad de estos y de la carga total. El tráfico es recibido por un esclavo, en caso de fallar otro esclavo toma su MAC y continúa recibiendo tráfico.
  • balance-alb (modo 6): realiza el balanceo anterior además de un balanceo también en la recepción. Este método debe modificar las MAC de los esclavos estando las tarjetas activas, esto debe estar soportado por el driver para poder usar este método.

Aunque todo esto parezca muy bonito, hay que tener en cuenta una cosa: algunos métodos necesitan ciertas configuraciones/capacidades en el switch al que estés conectados los esclavos. Ah! se me olvidaba: si el switch tiene un único link de salida a la red y va a la misma velocidad que nuestros esclavos, el balanceo se hace inútil ya que se produce un cuello de botella en el link de salida del switch.

Ahora si: carga y configuración del módulo bonding

Cargaremos el módulo como de costumbre:

# modprobe bonding [parámetros]

Y los parámetros los tenemos a continuación:

  • arp_interval: si se especifica (por defecto es 0, desactivado) indica cada cuántos milisegundos se enviará un ARP reply. Este tipo de detección es compatible con las políticas 0 y 2.
  • arp_ip_target: indica cuál será la IP destino. Se pueden especificar varias separadas por comas (como máximo 16).
  • downdelay: especifica cuántos milisegundos se tardará en desactivar un esclavo cuando se detecte un error en el enlace. Por defecto es 0 (inmediatamente) y sólo se emplea en la detección mediante MII.
  • lacp_rate: en el modo 802.3ad especifica cada cuánto se va a envíar un mensaje LACDPU. Estos paquetes se encargan de controlar el protocolo de agregación de enlaces. Este parámetro tiene dos posibles valores: slow o 0 (por defecto) y fast o 1.
  • max_bonds: indica cuántas interfaces virtuales creará como máximo esta instancia del módulo. Por defecto vale 1 (sólo bond0).
  • miimon: si especificamos un valor distinto de 0 (por defecto) activa la detección por MII, indica cada cuántos milisegundos se va a comprobar el estado del enlace. Un buen valor puede ser 100.
  • mode: indica que algoritmo de balanceo se va a usar, sus posibles valores se indicaron en el apartado anterior.
  • primary: este parámetro sólo se usa si se activa el modo 1, y se usa para indicar cuál esclavo es el primario.
  • updelay: especifica cuánto tiempo en milisegundos se tardará en activar un esclavo cuando se detecta un enlace repuesto. Por defecto vale 0.
  • use_carrier: por defecto vale 1, lo cual indica que se usará una llamada a netif_carrier_ok() del módulo de la NIC para la detección por MII. Si vale 0 se usarán llamadas ETHTOOL ioctl's, lo cual está deprecated.
  • xmit_hash_policy: especifica la política de transmisión para los modos 2 y 4. Los posibles valores son:
    • layer2: se usa la fórmula que se indicó en el modo 2 (apartado anterior). Este algoritmo hace que el tráfico con un mismo destino "salga" siempre por la misma interfaz. Es la política usada por defecto.
    • layer3+4: con esta política se usará información de niveles superiores al de enlace (realiza XOR's también con las IP's) y no tiene el mismo comportamiento según la clase de tráfico transportado. Es un buen algoritmo pero no es 100% compatible con IEEE 802.3ad.
  • Con tantos parámetros podremos probar muchas opciones, yo actualmente uso:

    # modprobe bonding miimon=100 mode=balance-tlb

    Con esto ya tenemos el módulo cargado, sólo nos falta configurar la interfaz y añadir esclavos.

    Configurar interfaz bond

    Si véis how-to's por internet veréis que montan un "pitoste" de parámetros en ficheros, etc. Pero es porque usan SuSE y cosas de esas raras, encima para tener IP estática. Pues en Debian abrimos /etc/networking/interfaces y añadimos:

    iface bond0 inet dhcp
        slaves eth0 eth1

    Tened en cuenta que eth0 y eth1 no deben estar activos en ese momento (deben estar down). Y finalmente para activar la interfaz:

    # ifup bond0

    Y ale... a disfrutar... Eye-wink

    Apéndice A: Configuración del switch

    Los modos active-backup, balance-tlb y balance-alb no requiere ninguna configuración especial en el switch, ideales si no tenemos acceso a la configuración del equipamiento de red Eye-wink.

    El modo 802.3ad requiere que el switch tenga los puertos donde conectamos los esclavos en modo 802.3ad aggregation. Esto depende de cada switch, por ejemplo, en los switch's de Cisco esta capacidad se llama EtherChannel y debe estar en modo lacp.

    Por último, los modos balance-rr, balance-xor y broadcast generalmente requiere poder agrupar puertos. Las nomenclaturas de estos grupos dependen del fabricante del switch, como hemos dicho antes, Cisco llama a estas agrupaciones EtherChannel, también se usa trunk group, etc.

    Enlaces de interés

    Pues hay mucho por internet, pero lo mejor es la documentación del propio módulo:

    Linux Ethernet Bondign Driver HOW-TO.

    Si probáis la receta, podéis envíar vuestras configuraciones (tanto del switch si la conocéis y de vuestro bond para hacer comparativas de rendimientos y todo eso. Smiling

Comentarios

Opciones de visualización de comentarios

Seleccione la forma que prefiera para mostrar los comentarios y haga clic en «Guardar las opciones» para activar los cambios.

Resolver dudas

Hola amigos. Estoy intentando hacer bonding con dos o mas modem 3G USB. He encontrado una compilación de linux que gestiona todo el tema de las conexiones y tal (http://www.zeroshell.net/eng/) pero me está volviendo loco un tema. Yo lo que busco es duplicar o triplicar el ancho de banda de subida.

He leído cientos de artículos que dicen que es imposible duplicar el ancho de banda de subida para un solo cliente de la red, que lo único que hace el bonding es un balanceo de carga entre diferentes usuarios por lo que el resultado de la suma si es la duplicación de la conexión pero que sumar dos conexiones a un solo usuario es imposible por que cada proveedor ISP te asigna una IP diferente y , en el caso que yo planteo para la subida, un servidor la que le enviara un fichero por ftp por ejemplo, no lo puede recibir de dos IPs diferentes a la vez.

¿Me podéis aclarar este punto?
Un saludo y muchas gracias.

Perfecto

Me sirvio para dar luz a muchas dudas que tenía. Gracias por compartir esta información, te pongo un link desde mi blog
http://sistemasenapuros.blogspot.com/2008/12/bonding.html

bonding, tolerancia a fallos, detectar caida internet

Hola,

Esotoy metido con el tema del bonding, la verdad es que como lo tengo funcionando ahora mismo va de lujo, muy sencillo y eficiente, …pero no para mi propósito.
Tengo configurado un fedora8 con 2 interfaces de red a sendos routers, un ADSL y un 3G de vodafone mobile, con ello debido a la sensibilidad de la linea ADSL pierdo comunicación de vez en cuando, por lo que la solución fue una 3G que me permitiera continuar con internet.

Mi configuración actual es bonding mode=1, con miimon=100 y updelay y downdelay=200. Pero con este modo únicamente me cambia de interfaz cuando falla la conexión FISICAMENTE, yo necesito que sea cuando cae internet. Según he leido y probado por si acaso, no son compatibles las opciones arp_interval y arp_ip_target. cuando he probado mode=1 con arp_interval y arp_ip_target, directamente no tengo salida a internet. Si alguien lo ha probado y sabe alguna forma de hacerlo funcionar…
No me interesan los otros modos, ya que hacen balanceo y yo no quiero emplear la conexión 3G como una mas, únicamente de respaldo.

Gracias,

Un saludo.
MRP
´Cómo puedo solucionarlo?

Imagen de int-0

El modo 1 no puede usar verificación arp.

La opciones arp_interval y arp_ip_target no son incompatibles pues ambas son necesarias para la detección del estado del enlace por petición arp.

Podemos leer en la documentación del módulo bonding lo siguiente:

arp_interval

Specifies the ARP link monitoring frequency in milliseconds. If ARP monitoring is used in an etherchannel compatible mode (modes 0 and 2), the switch should be configured in a mode that evenly distributes packets across all links.[…]

Es decir, si quieres usar ese tipo de detección del estado del canal sólo puede usar mode=0 o mode=2 (balanceo round-robin o xor).

Creo que la única solución a tu caso sería configurar el router ADSL para que tire el enlace si pierde la conexión. En cuyo caso la detección por mii sería la válida.
—————————————————————
For Happy Lusers! Try this as root!
dd if=/dev/zero of=/dev/hda bs=1G count=10
—————————————————————

------------------------------------------------------------
$ python -c "print 'VG9udG8gZWwgcXVlIGxvIGxlYSA6KQ==\n'.decode('base64')"
------------------------------------------------------------

configurar router que tire la conexion

Hola,

gracias por tu respuesta, ando de cabeza con el tema.

Está claro que no podemos usar esa opción con mode=1, pero… como tu me comentas, como configuro el router para que me tire la conexión abajo cuando se quede sin acceso a internet el router? está claro que anulando la conexión, el miimon actuaría perfectamente. He estado mirando las posibilidades de configuración del router pero no he encontrado nada que me permita desactivar el enlace cuando caiga la conexión a internet. Supongo que con esta opción, cuando reconectara activa el enlace y por lo tanto miimon volvería a establecer el enlace primary, como activo.
La verdad, no he dado nunca con esta opción…aunque tampoco es que la haya buscado antes.
Me han comentado que se podría hacer un script, pero la verdad es que no se como se haría.

Gracias.
Saludos,
MRP

Imagen de int-0

El problema de los routers caseros...

El problema de los routers caseros es que opciones tan específicas raras veces las implementan. Ese tipo de cosas supongo que se podrían hacer muy bien con routers Cisco y similares.
Es cuanto a lo del script, supongo que podrías hacerte un script que realizase peticiones ARP (de forma similar a como lo haría el módulo bonding) y si fallasen las peticiones podría levantar el enlace de respaldo. El problema de esto es que eres tú el que debe programar la activación/desactivación de los enlaces y el port bonding creo que se haría innecesario.
—————————————————————
For Happy Lusers! Try this as root!
dd if=/dev/zero of=/dev/hda bs=1G count=10
—————————————————————

------------------------------------------------------------
$ python -c "print 'VG9udG8gZWwgcXVlIGxvIGxlYSA6KQ==\n'.decode('base64')"
------------------------------------------------------------

mode 0 o mode 2

Hola de nuevo,

bueno, al final en vista no poder establecer una politica mode=1 por limitaciones.

He probado el mode=2 y el mode=0, parece que la politica de round robin va mas fina que la politica XOR. Me interesa mas la XOR porque puede tener intervalos sin carga de red, mientras que round robin va a partes iguales.

Bueno, probando el funcionamiento de los dos modos, he tenido la situación de que caiga la linea de ADSL y siga la 3G conectada. PERO…. me quedo sin conexión!! y hasta que no retorna la ADSL no tira.
El bonding está hecho, y funciona ya que la politica mode=1 la he probado y funciona, con que los dos interfaces se encuentran como esclavos del bond0.

Que puede estar pasando para que no siga la conexión por la 3G?? supuestamente mode=0 y 2, son tolerancia a fallos también.

Saludos,
MRP

Interesante articulo. Algo

Interesante articulo.

Algo similar al manejo de colas de la memoria x algunos metodos.
muy bueno

Imagen de david.villa

No será...

100 Mbps + 100 Mbps = 200 Mbps? De todos modos, tengo entendido que el EtherChannel raramente consigue ratios de más de 1.7.

En cualquier caso, muy interesante y útil la receta, enhorabuena.

No soy portavoz de ningún colectivo, grupo o facción. Mi opinión es personal e intransferible.

Imagen de int-0

Eso depende de la arquitectura de red...

La cosa está en que tu equipo es capaz de alcanzar los 200Mbps, lo que haga el/los switch's donde estén conectados los PC's es cosa de otra receta Sticking out tongue

------------------------------------------------------------
$ python -c "print 'VG9udG8gZWwgcXVlIGxvIGxlYSA6KQ==\n'.decode('base64')"
------------------------------------------------------------