Channel Bonding (ou Port Trunking) é uma técnica especial que permite agregar interfaces de rede (geralmente ethernet) em interfaces lógicas que se comportam como um único link físico (dependendo da configuração). Esta técnica é utilizada principalmente para prover tolerância a falhas entre links, alta disponibilidade (redundância) e balanceamento.
Configuração: (Slackware 12.0)
O primeiro passo é habilitar o módulo do Kernel do Linux que faz isso tudo funcionar, chama-se "bonding".
CONFIG_BONDING=m
Não configure como builtin, pois não conseguiremos passar parâmetros como fazemos com módulos ao carregá-los.
Para verificar o suporte ao bonding como módulo no Kernel utilizado faça o seguinte:
# modprobe --list | grep bonding /lib/modules/2.6.21.5-smp/kernel/drivers/net/bonding/bonding.ko
Neste caso temos o Kernel do Linux no Slackware 12.0 com a configuração padrão da distribuição (2.6.21.5 com suporte a SMP), já com o bonding como módulo (tornando desnecessário recompilar o Kernel).
No exemplo a seguir utilizaremos duas placas de rede Gigabit da D-Link e um Switch gerenciável da SMC para prover redundância entre as duas interfaces e tolerância a falhas.
O switch é o SMC-8024L2 e as placas de rede são a DGE-530T.
Configurei o switch para agregar as duas portas utilizadas (já que utilizarei o modo 0); como não faz muito sentido exibir a interface Web do switch aqui, abaixo segue a configuração utilizada obtida através da porta serial (CLI):
> Aggr Configuration
Aggr Configuration:
Groups:
11,12
Lacp status
None
Mode: dmac
Operational Status
Groups:
11,12
Ou seja, as portas 11 e 12 do switch estão agregadas num único grupo (trunk), não utilizei o 802.3ad (LACP) e o modo de operação é baseado em uma política de destination MAC's.
O próximo passo, após recompilar o Kernel com suporte ao bonding é compilar o utilitário ifenslave, que se encontra na documentação do próprio Kernel:
/usr/src/linux/Documentation/networking/ifenslave.c
Para compilar o ifenslave faça o seguinte (é possível controlar também o Channel Bonding através do sysfs):
# gcc -Wall -O -I/usr/src/linux/include ifenslave.c -o ifenslave # chown root.bin ifenslave # chmod 0755 ifenslave # cp ifenslave /usr/sbin
Agora basta configurar as interfaces, o primeiro passo é remover os módulos das placas de rede e do Port Trunking, caso já estejam carregados.
# rmmod bonding skge 2> /dev/null
skge é o módulo utilizado pelas placas de rede em questão.
Feito isto carregamos novamente os módulos e configuramos o Channel Bonding no modo 0, ou seja, load balancing (round-robin):
# modprobe bonding mode=0 miimon=100 # modprobe skge
miimon especifica em ms a freqüência com que as interfaces configuradas em modo slave serão verificadas e consideradas inativas caso não haja resposta (conseqüentemente removidas da configuração ativa).
Nos logs do sistema teríamos o seguinte:
skge 1.10 addr 0xfdef8000 irq 17 chip Yukon-Lite rev 9 skge eth0: addr 00:15:e9:4a:xx:yy skge 1.10 addr 0xfdef4000 irq 18 chip Yukon-Lite rev 9 skge eth1: addr 00:15:e9:4a:xx:zz Ethernet Channel Bonding Driver: v3.1.2 (January 20, 2007) bonding: MII link monitoring set to 100 ms
Sobre os modos de operação disponíveis:
0 (balance-rr), transmite os pacotes em ordem seqüencial do primeiro slave ao último. Provê tolerância a falhas e balanceamento. É o modo default, é também o único modo que permite com que o tráfego seja distribuído entre as interfaces slave simultaneamente (ex. duas placas 10/1000 serão uma única interface 2x(10/1000), ou seja, 2Gbit max).
1 (active-backup), apenas um slave no etherchannel está ativo, os demais apenas serão ativados (um de cada vez) no caso de falha do slave ativo. Provê tolerância a falhas e alta disponibilidade.
2 (balance-xor), transmite os pacotes adotando uma política baseado em hashs, provê praticamente as mesmas funcionalidades do modo 0. É possível configurar políticas alternativas modificando o parâmetro xmit_hash_policy ao carregar o módulo. A política padrão é baseada em MAC's (origem/destino XOR'd).
3 (broadcast), transmite todos os pacotes em todos os slaves. Provê tolerância a falhas e alta disponibilidade.
4 (802.3ad), agregação dinâmica de links. é necessário um switch que suporte 802.3ad e que o ethtool consiga configurar os parâmetros speed e duplex em todos os slaves. É necessário também alguma configuração extra no switch; no switch utilizado neste artigo esta configuração tem o nome LACP (IEEE 802.3ad Link Aggregation Protocol).
5 (balance-tlb), load-balance adaptável. Não requer nenhum suporte especial do switch, o tráfego de saída é distribuído de acordo com a carga em cada slave. o tráfego de entrada utiliza um único slave, se ele falhar outro assume e clona o MAC do slave que estava ativo.
6 (balance-alb), de forma bem generalizada é modo 5 turbinado (tlb+rlb).
Voltando à configuração, agora ativamos as placas de rede (as duas D-Link Giga) e a interface lógica (o Channel Bonding).
# ip link set dev eth0 up # ip link set dev eth1 up # ip link set dev bond0 up
A interface bond0 irá clonar o MAC da primeira interface ethernet carregada no sistema, no caso a eth0. As duas interfaces configuradas como slave terão também o mesmo MAC da primeira eth detectada.
Poderíamos omitir os "set dev ethx up", pois ao ativarmos o bond0 isso é feito automaticamente.
Feito isto configuramos os endereços de rede e a rota padrão da forma habitual:
# ip address add x.y.z.26/29 broadcast x.y.z.31 dev bond0 # ip route add default via x.y.z.25 dev bond0
O passo final é executar o utilitário que compilamos para ativar efetivamente o Port Trunking/Channel Bonding no sistema:
# ifenslave bond0 eth0 eth1
As interfaces estarão configuradas da seguinte maneira:
7: eth0: <BROADCAST,MULTICAST,SLAVE,UP,10000> [...] master bond0 qlen 1000
link/ether 00:15:e9:4a:xx:zz brd ff:ff:ff:ff:ff:ff
8: eth1: <BROADCAST,MULTICAST,SLAVE,UP,10000> [...] master bond0 qlen 1000
link/ether 00:15:e9:4a:xx:zz brd ff:ff:ff:ff:ff:ff
9: bond0: <BROADCAST,MULTICAST,MASTER,UP,10000> mtu 1500 qdisc noqueue
link/ether 00:15:e9:4a:xx:zz brd ff:ff:ff:ff:ff:ff
inet x.y.z.26/29 brd x.y.z.31 scope global bond0
Notem que os MAC's estão todos clonados (são todos iguais) e que as interfaces eth0 e eth1 estão ativas e configuradas como slave. A única interface com endereços configurados é o Port Trunking criado.
Para verificar o status da configuração (Channel Bonding), faça o seguinte:
# cat /proc/net/bonding/bond0 Ethernet Channel Bonding Driver: v3.1.2 (January 20, 2007) Bonding Mode: load balancing (round-robin) MII Status: up MII Polling Interval (ms): 100 Up Delay (ms): 0 Down Delay (ms): 0 Slave Interface: eth0 MII Status: up Link Failure Count: 0 Permanent HW addr: 00:15:e9:4a:xx:yy Slave Interface: eth1 MII Status: up Link Failure Count: 0 Permanent HW addr: 00:15:e9:4a:xx:zz
O interessante dessa configuração (modo 0) é que se um dos links "cair" o sistema continua ativo e o link ethernet não para, na verdade nem percebemos o que aconteceu.
Exemplo (desconectei um dos cabos cat6 e num dos terminais deixei monitorando o link):
Nov 14 16:26:49 xxxxx kernel: skge eth1: Link is down. Nov 14 16:26:50 xxxxx kernel: bonding: bond0: link status \ definitely down for interface eth1, disabling it
Ou seja, a interface foi removida do Channel Bonding e o link continuou ativo. Ao reconectar novamente o cabo a interface automaticamente será reinserida no Channel Bonding.
Os modos 0, 2 e 3 requerem suporte especial e configuração do switch (as portas devem ser configuradas como membros de grupos Trunk/etherchannel).
O modo 6 requer suporte do switch ao padrão 802.3ad. Os demais não requerem suporte especial do switch.
Lembre-se de remover as rotas nas interfaces agregadas como slave, apenas a rota no etherchannel deve ser configurada (e a rota default, claro).
Exemplo:
# ip route show x.y.z.24/29 dev bond0 proto kernel scope link src x.y.z.26 127.0.0.0/8 dev lo scope link default via x.y.z.25 dev bond0
Podemos também utilizar o sysfs (como já foi citado) para configurar o Port Trunking, tornando desnecessário o uso do ifenslave, um exemplo que executa a configuração citada acima seria:
# modprobe bonding # modprobe skge # echo 0 > /sys/class/net/bond0/bonding/mode # ip address add x.y.z.26/29 broadcast x.y.z.31 dev bond0 # ip route add default via x.y.z.25 dev bond0 # echo 100 > /sys/class/net/bond0/bonding/miimon # echo +eth0 /sys/class/net/bond0/bonding/slaves # echo +eth1 /sys/class/net/bond0/bonding/slaves
Ou seja, carregamos os módulos, setamos o modo de operação, configuramos o endereço e rota padrão, setamos a frequencia de checagem e incluímos as interfaces em modo slave.
Para verificar o uso das interfaces slave, poderíamos fazer algo como:
# for x in 0 1; do ifconfig eth$x | grep bytes; done
RX bytes:4267502419 (3.9 GiB) TX bytes:2742529903 (2.5 GiB)
RX bytes:1341729996 (1.2 GiB) TX bytes:2464703001 (2.2 GiB)
Poderíamos fazer o mesmo via SNMP:
# snmpwalk -v1 -c public x.y.z.26 | grep -i eth | head -2 IF-MIB::ifDescr.7 = STRING: eth0 IF-MIB::ifDescr.8 = STRING: eth1
E as taxas recuperaríamos da seguinte maneira (agora sabemos quais IfDescr utilizar):
# snmpget -v1 -c public x.y.z.26 IF-MIB::ifOutOctets.8 IF-MIB::ifOutOctets.8 = Counter32: 2617173305 # snmpget -v1 -c public x.y.z.26 IF-MIB::ifOutOctets.7 IF-MIB::ifOutOctets.7 = Counter32: 2894673522 # snmpget -v1 -c public x.y.z.26 IF-MIB::ifInOctets.8 IF-MIB::ifInOctets.8 = Counter32: 1604170366 # snmpget -v1 -c public x.y.z.26 IF-MIB::ifInOctets.7 IF-MIB::ifInOctets.7 = Counter32: 4267713431
Para tornar as informações acima mais user-friendly podemos utilizar softwares que utilizam SNMP e geram gráficos, como o mrtg ou o cacti.
--
referência: /usr/src/linux/Documentation/networking/bonding.txt


