você está aqui: Home  → Arquivo de Mensagens

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