você está aqui: Home  → Arquivo de Mensagens Workshop Gratuito: Os Segredos do Shell, com o Prof. Julio Neves

Balanceamento de links com ip dinamico

Colaboração: Altemir Braz Dantas Junior

Data de Publicação: 10 de outubro de 2011

Sempre fiz balanceamento de links com ip fixo usando iproute2 + iptables, até que um cliente que tinha 3 links de internet com ip dinamico, ai pensei "puts vai zoar as rotas do balanceamento toda hora que trocar o gateway, vou ter que criar varios scripts para ficar monitorando e trocar a rota, vamos googlear".

O google é meu pastor e nada me faltará. rsrsrsr

Achei o que queria e vou apresentar-lo meu salvador dhclient-script, disponível a partir da versão 3 do dhclient.

Verifiquei que através dele eu poderia pegar informações importantes como as do exemplo abaixo

OBS: Nao mencionarei regras de iptables (INPUT, OUTPUT, FORWARD , MASQUERADE e etc) aqui, somente a criacao das rotas

reason='RENEW'
interface='eth1'
medium=''
alias_ip_address=''
new_ip_address='189.xxx.xxx.xxx'
new_subnet_mask='255.255.240.0'
new_domain_name=''
new_domain_search=''
new_domain_name_servers='8.8.8.8 4.2.2.2'
new_routers='189.xxx.xxx.1'
new_static_routes=''
old_ip_address='189.yyy.yyy.yyy'
old_subnet_mask='255.255.240.0'
old_domain_name='spo.virtua.com.br'
old_domain_search=''
old_domain_name_servers='8.8.8.8 4.2.2.2'
old_routers='189.yyy.yyy.1'
old_static_routes=''

E o melhor ele me retorna como variaveis para eu usar no meu shell script na hora de cada ação

O dhclient-script usa o Bourne Shell.

Para voces entenderem melhor leiam o man.

Ambiente

  • eth0 - rede interna
  • eth1 - link1 100MG
  • eth2 - link2 20MG
  • eth3 - link3 4MG
  • link1 usei a marca 1 e peso 6
  • link2 usei a marca 2 e peso 3
  • link3 usei a marca 3 e peso 1

Como uso debian vou mostrar como fiz nesta distribuição.

Instalando pacotes necessários

apt-get install dhclient3 ipcalc iproute2

Primeiramente vou criar as tabelas no iproute2

echo "201	link1" >>  /etc/iproute2/rt_tables
echo "202	link2" >>  /etc/iproute2/rt_tables
echo "203	link3" >>  /etc/iproute2/rt_tables

Agora cria minhas functions

mkdir /etc/scripts
vi /etc/scripts/function.sh

Contendo o seguinte

# recebe a interface da rede e retorna o nome da tabela cadastrada
pega_tabela(){
     DEV=$1
     case $DEV in
     eth1)
             TABELA="link1"
             return 1
             break
             ;;
     eth2)
             TABELA="link2"
             return 1
             break
             ;;
     eth3)
             TABELA="link3"
             return 1
             break
             ;;
     esac
}

# recebe a interface da rede e retorna o numero da marcacao para poder usar rotas pela marcacao feita pelo iptables
pega_marca(){
     DEV=$1
     case $DEV in
     eth1)
             MARK="1"
             return 1
             break
             ;;
     eth2)
             MARK="2"
             return 1
             break
             ;;
     eth3)
             MARK="3"
             return 1
             break
             ;;
     esac
}

# recebe a interface da rede e retorna o peso para fazer o balanceamento

pega_peso(){
     DEV=$1
     case $DEV in
     eth1)
             PESO="6"
             return 1
             break
             ;;
     eth2)
             PESO="3"
             return 1
             break
             ;;
     eth3)
             PESO="1"
             return 1
             break
             ;;
     esac
}

# recebe a tabela e retorna o ip do gateway da mesma
pega_gateway(){
     TABELA=$1
     GATEWAY=$(ip route show table $TABELA | grep default | awk -F' ' '{ print $3 }')
}


# recebe a tabela e deleta todas as rotas da mesma
del_rotas(){
     /sbin/ip route flush table $1
}

# recebe a tabela e deleta todas as regras  da mesma
del_regras(){
     ip rule show | grep $1 | cut -d : -f2 | while read RULES;  do ip rule del $RULES ; done
}

# recebe a tabela,ip,marca  e cria regras de roteamento para aquela tabela
add_regras(){
     TABELA=$1
     IP=$2
     MARK=$3
     ip rule add fwmark $MARK table $TABELA
     ip rule add from $IP table $TABELA
}

# recebe a tabela,ip,interface,ip da rede e o ip do gateway  para criar as rotas para aquela tabela
add_rotas(){
     TABELA=$1
     IP=$2
     DEV=$3
     REDE=$4
     GW=$5
     /sbin/ip route add $REDE dev $DEV src $IP table $TABELA
     /sbin/ip route add default via $GW dev $DEV table $TABELA
}

# deleta todas as rotas padrao
del_rotas_padrao(){
     # deletando as rotas default
     # deleta a rota criada pelo dhcp
     /sbin/ip route del default
     # deleta a rota do balanceamento
     /sbin/ip route del default
}

# recebe interface,ip do gateway e peso para criar as regras de balanceamento
add_rota_balanceamento(){
     DEVNEW=$1
     GWNEW=$2
     PESONEW=$3

     case $DEVNEW in
     eth1)
             pega_tabela eth2
             pega_peso eth2
             pega_gateway $TABELA
             TABELA2=$TABELA
             PESO2=$PESO
             GW2=$GATEWAY
             DEV2=eth2

             pega_tabela eth3
             pega_peso eth3
             pega_gateway $TABELA
             TABELA3=$TABELA
             PESO3=$PESO
             GW3=$GATEWAY
             DEV3=eth3
             ;;

     eth2)
             pega_tabela eth1
             pega_peso eth1
             pega_gateway $TABELA
             TABELA2=$TABELA
             PESO2=$PESO
             GW2=$GATEWAY
             DEV2=eth1

             pega_tabela eth3
             pega_peso eth3
             pega_gateway $TABELA
             TABELA3=$TABELA
             PESO3=$PESO
             GW3=$GATEWAY
             DEV3=eth3
             ;;
     eth3)
             pega_tabela eth1
             pega_peso eth1
             pega_gateway $TABELA
             TABELA2=$TABELA
             PESO2=$PESO
             GW2=$GATEWAY
             DEV2=eth1

					 pega_tabela eth2
             pega_peso eth2
             pega_gateway $TABELA
             TABELA3=$TABELA
             PESO3=$PESO
             GW3=$GATEWAY
             DEV3=eth2
             ;;
     esac


     if [ "$GWNEW" == "0" ]; then
             if [ "$GW2" != "" -a $GW3 != "" ]; then
                     /sbin/ip route add default nexthop via $GW2 dev $DEV2 weight $PESO2 nexthop via $GW3 dev $DEV3 weight $PESO3
             else
                     if [ "$GW2" != "" ]; then
                             /sbin/ip route add default via $GW2
                     else
                             /sbin/ip route add default via $GW3
                     fi
             fi
     else
             if [ "$GW2" != "" -a $GW3 != "" ]; then
                     /sbin/ip route add default nexthop via $GWNEW dev $DEVNEW weight $PESONEW nexthop via $GW2 dev $DEV2 weight $PESO2 nexthop via $GW3 dev $DEV3 weight $PESO3
             else
                     if [ "$GW2" != "" ]; then
                             /sbin/ip route add default nexthop via $GWNEW dev $DEVNEW weight $PESONEW nexthop via $GW2 dev $DEV2 weight $PESO2
                     else
                             if [ "$GW3" != "" ]; then
                                     /sbin/ip route add default nexthop via $GWNEW dev $DEVNEW weight $PESONEW nexthop via $GW3 dev $DEV3 weight $PESO3
                             else
                                     /sbin/ip route add default via $GWNEW
											fi

                     fi
             fi

     fi
     return 1;
}

Criado o arquivo das functions agora vou criar os scripts para o dhclient-script

Dentro do diretorio /etc/dhcp/ existem dois diretorios o dhclient-enter-hooks.d/ e o dhclient-exit-hooks.d/ e o arquivo dhclient.conf

No arquivo dhclient.conf procure a linha comentada

#prepend domain-name-servers

Descomente e coloque os seguintes DNS publicos

prepend domain-name-servers 8.8.8.8 4.2.2.2;

Assim toda vez que o servidor dhcp nos atribuir seus servidores DNS ele vai adicionar esses 2 antes do dele.

Em relação aos diretorios antes dele, fazer alteracoes em nosso /etc/resolve.conf o dhclient script vai checar se há scripts primeiramente dentro de dhclient-enter-hooks.d/ usando o "." (ponto).

Quem usa Bourne Shell (bash) sabe que é como um include no diretorio. Depois de executar ele faz a mesma operacao no diretorio dhclient-exit-hooks.d/

Para mais informações

man dhclient-script

Criei então o seguinte script dentro do diretorio dhclient-enter-hooks.d/:

vi /etc/dhcp/dhclient-enter-hooks.d/rotas_avancadas

Contendo


# da um include na minha function
. /etc/scripts/function.sh

# ok = 0 -> link fora - deleta rotas para esse link
# ok = 1 -> link ok e novo ip - altera rotas desse link
# ok = 2 -> link ok e o ip nao mudou portanto nao faca nada

# setei ok = 2 para nao fazer nada

ok=2

if [ "$reason" == "REBOOT" -o "$reason" == "RENEW" -o "$reason" == "BOUND" -o "$reason" == "REBIND" ]; then
    
     # Se o novo ip for igual a nada setar ok = 0
     if [ "$new_ip_address" == "" ]; then
             ok=0
     fi
    
     # Se o novo ip tem o inicio igual 192 quer dizer que o dhcp me deu ip porem esta sem internet entao seta ok = 0
     inicioip=$(echo $new_ip_address | cut -d "." -f 1)
     if [ "$inicioip" == "192" ]; then
             ok=0
     fi

		  # se o ok continua igua a 2 é porque ele passou dos itens acima
     if [ "$ok" == "2" ];then
     			 # se o ip diferente do antigo seto o ok=1
             if [ "$new_ip_address" != "$old_ip_address" ];then
                     ok=1;
             fi
     fi

fi

# Se aontecer uma das acoes abaixo é que o servidor dhcp falhou entao seto o ok=0
if [ "$reason" == "FAIL" -o "$reason" == "TIMEOUT" -o "$reason" == "EXPIRE" ]; then
     ok=0;
fi

Depois disso criei o seguinte script

vi /etc/dhcp/dhclient-exit-hooks.d/rotas_avancadas

Contendo


# ja tenho os meus ok definidos no script anterior e minha functions incluidas tambem ai faco minhas acoes
if [ "$ok" == "1" ]; then
		  # pego minhas variaveis
		  pega_tabela $interface
     pega_marca $interface
     pega_peso $interface
   
		  # calcula o ip da rede       
     ipcalcule=$(echo "$new_ip_address/$new_subnet_mask")
     my_new_network=$(ipcalc -n $ipcalcule | grep Network | cut -b 12-32)
    
     # deleta regra antiga e cria regras novas
     del_regras $TABELA
     add_regras $TABELA $new_ip_address $MARK
    
     #deleta rotas antigas e cria novas
     del_rotas $TABELA
     add_rotas $TABELA $new_ip_address $interface $my_new_network $new_routers
     del_rotas_padrao
     add_rota_balanceamento $interface $new_routers $PESO
  
fi

if [ "$ok" == "0" ]; then
     pega_tabela $interface
     del_rotas $TABELA
     del_regras $TABELA
     del_rotas_padrao
     add_rota_balanceamento $interface 0 0
fi


Agora é só executar

dhclient -v eth1
dhclient -v eth2
dhclient -v eth3

Olhar como ficou as rotas

ip route show
ip route show table link1
ip route show table link2
ip route show table link3

Para ver como ficaram as regras:

ip rule show

Para testar com o ip route get para ver qual a rota que ele usaria para sair para um determinado destino:

ip route get 8.8.8.8
ip route get 4.2.2.2
ip route get 174.120.154.93

E fazer seus testes

Altemir Braz Dantas Junior (jocajuni) http://acessa.me/@joca, http://acessa.me - crie seu atendimento online gratuito

Linux e Mercado

Colaboração: Fátima Conti

Visto em http://visualoop.tumblr.com/post/9430080645/linux-market-shares



Veja a relação completa dos artigos de Altemir Braz Dantas Junior