Como medir desempenhos de conectividade em redes de computadores, com Iperf3 e OpenWRT

Intro

“O wifi tá lento."

Qualquer pessoa que já tenha administrado uma rede de computadores sabe que essa frase costuma anteceder dores de cabeça, ranger de dentes e tempo perdido. Isso porque, na grande maioria das vezes, essa será a única informação disponível para essa pessoa, que terá que se virar do avesso para descobrir o que está acontecendo… isso quando há algo realmente acontecendo, o que nem sempre é o caso. Portanto, para evitar a eterna controvérsia de “aqui está normal”, “funciona perfeitamente na minha máquina” e “feche o utorrent, porra”, vamos desenvolver medidores de performance de rede utilizando OpenWRT e Iperf versão 3.

Os procedimentos descritos aqui, em princípio, funcionam em qualquer roteador com OpenWRT, tanto na versão 21.02 quanto na 19.07.8. Todos os exemplos aqui demonstrados utilizam a versão 19 e, portanto, se aplicam a dispositivos mais antigos cujo hardware é bastante limitado para os padrões atuais (32MB RAM e/ou 4MB de storage). Com isso, podemos reciclar dispositivos que não tem mais suporte do fabricante nem atualizações oficiais de software há uma década, e que continuariam “encostados” sem outra utilidade.

Conteúdo do artigo:

  • instalação do iperf3 em roteadores com OpenWRT, e suas configurações como serviço de sistema;
  • como configurar um botão do dispositivo para ligar e desligar o serviço;
  • como associar leds ao status do serviço (ligado/desligado), em conjunto com o botão acima;
  • como executar testes à partir de outros dispositivos (desktop & mobile);

Instalação & Configuração

Como tudo o mais na vida, há diversas maneiras diferentes de executar esse tipo de procedimento. Logo de saída, antecipo que é necessário utilizar linha de comando para implementar os exemplos demonstrados, pois não é possível usar a interface Luci para criar e editar arquivos dentro do firmware do roteador.

O OpenWRT conta com um gerenciador de pacotes semelhante a qualquer outra distro Linux, portanto é necessário atualizar os repositórios-fonte antes de podermos instalar algo. Por ser um aplicativo pequeno, de poucos kilobytes, é possível instalar o iperf3 até mesmo nesses dispositivos com 4MB de espaço. Também é possível incluí-lo na lista de pacotes instalados ao utilizar o image builder: nesse caso, os arquivos mencionados abaixo seriam integrados diretamente ao sistema.

Primeiro, devemos nos conectar ao roteador e executar os seguinte comandos:

$ ssh root@roteador-alvo
# opkg update
# opkg install iperf3

Uma porta TCP deve ser liberada explicitamente no firewall do roteador, para que o Iperf possa receber conexões vindas de outros dispositivos na rede. O teste propriamente dito acontece em um fluxo de rede específico, separado deste daemon e definido pelo lado cliente, que pode, por exemplo, invocar UDP ao invés de TCP - o que deverá ser igualmente liberado no firewall. Para evitar conflito com outros serviços de rede, será usada a porta 5005 ao longo do exercício. Pode-se escolher qualquer outra porta alta, desde que esteja configurada consistentemente em todos os lugares mencionados.

A seguinte regra deve ser adicionada ao arquivo /etc/config/firewall:

config rule
	option name 'Allow-iperf3'
	option target 'ACCEPT'
	list proto 'tcp'
	list proto 'udp'
	option dest_port '5005'
	option src 'lan'

Em ordem: define-se um nome para a regra (Allow-iperf3), a ação a ser tomada (ACCEPT, ou seja, aceitar conexões), os protocolos de rede listados individualmente (tcp + udp) e a porta de destino 5005.

A ultima opção (src) deve indicar a interface de rede a ser medida, sendo que devemos prestar atenção se é uma rede interna ou uma rede diretamente exposta à internet. Embora seja possível utilizar o iperf3 em ambas, os casos descritos aqui preveem apenas redes internas.

Para que a nova regra do firewall seja aplicada:

# /etc/init.d/firewall reload

Dois arquivos, a serem criados, definem a configuração do serviço:

  • /usr/bin/iperfd : para iniciar uma instância do iperf3 em modo servidor e como daemon (-s -D), escutando conexões TCP em todas as interfaces IPv4 disponíveis, sempre na porta 5005 (-B 0.0.0.0 -p 5005). Eventos da aplicação serão logados no arquivo designado em logfile. Endereço IP e porta podem ser modificados à vontade, desde que estejam igualmente configurados no firewall, como visto acima. Outros parametros podem ser adicionados à execução da instancia, como por exemplo: -V para verbose e -d para debug. Há suporte ipv6 também.

      cat <<_EOF_ > /usr/bin/iperfd
      /usr/bin/iperf3 -s -D -B 0.0.0.0 -p 5005 --logfile /var/log/iperf3-server.log
      _EOF_
    
      chmod +x /usr/bin/iperfd
    
  • /etc/init.d/iperfd : para manejar essa instancia enquanto serviço do sistema. logger faz com que o evento executado apareça no log do sistema, e as instruções comentadas dizem respeito ao LED que será associado ao iperf-server (ver abaixo):

      ### copiar daqui pra baixo...
      #!/bin/sh /etc/rc.common
      # (C) 2019 Fernao Vellozo
    
      START=90
    
      boot() { 
      	logger "iperf3 daemon started on boot"
      	uci set system.led_sys.trigger='default-on'
      	uci commit
      	/usr/bin/iperfd
      	/etc/init.d/led reload
      }
    
      start() {
      	logger "iperf3 daemon started" 
      	uci set system.led_sys.trigger='default-on'
      	uci commit
      	/usr/bin/iperfd
      	/etc/init.d/led reload
      }
    
      stop() { 
      	logger "iperf3 daemon stopped"
      	killall iperf3
      	uci set system.led_sys.trigger='none'
      	uci commit
      	/etc/init.d/led reload
      }
    
      restart() {
      	logger "iperf3 daemon restarting"
      	killall iperf3
      	/usr/bin/iperfd
      	logger "iperf3 daemon restarted"
      }
      ### ... até a linha de cima
    
      ### para que seja executável
      # chmod +x /etc/init.d/iperfd
    

Podemos configurar o serviço para que seja iniciado no boot, se preciso.

# /etc/init.d/iperfd enable

Nesse caso, devemos levar em consideração se é desejável deixar o serviço ativo (portanto exposto) o tempo todo, pois ele pode ser manipulado e/ou explorado de maneira indevida.

Led Status

Para que o status do serviço seja devidamente associado ao led SYS quando aceso ou apagado, deve-se acrescentar esse bloco de código em /etc/config/system:

config led 'led_sys'
	option default '0'
	option sysfs 'XXX'
	option name 'iperf3'
	option trigger 'none'

Para pôr as modificações em efeito:

# /etc/init.d/system reload
# /etc/init.d/led reload

Com isso, o led “sys” deverá estar aceso enquanto o serviço estiver ativo, e apagar-se quando o serviço for desativado.

Botão ON/OFF

Por padrão no OpenWRT, apenas o botão de reset vem configurado, enquanto o botão wps não faz nada. Para atribuir funções a este botão, deve acrescentar um arquivo para interpretar as ações a serem executadas. Neste exemplo, o iperf3 será iniciado sempre que o botão for pressionado por 1 segundo ou menos. Outras funções serão descritas para que sejam executadas quando o botão for pressionado por X e Y segundos, mas nada será realmente excutado nesses casos:

# mkdir -p /etc/hotplug.d/button
# vi /etc/hotplug.d/buttons/00-button
source /lib/functions.sh

do_button () {
    local button
    local action
    local handler
    local min
    local max

    config_get button "${1}" button
    config_get action "${1}" action
    config_get handler "${1}" handler
    config_get min "${1}" min
    config_get max "${1}" max

    [ "${ACTION}" = "${action}" -a "${BUTTON}" = "${button}" -a -n "${handler}" ] && {
        [ -z "${min}" -o -z "${max}" ] && eval ${handler}
        [ -n "${min}" -a -n "${max}" ] && {
            [ "${min}" -le "${SEEN}" -a "${max}" -ge "${SEEN}" ] && eval ${handler}
        }
    }
}

config_load system
config_foreach do_button button

# chmod +x /usr/bin/iperfd-btn

O script /usr/bin/iperf-btn é executado pela ação do hardware, verificando se o serviço iperf3 está executando: se sim, o serviço será interrompido. Caso contrário, será iniciado.

### copiar daqui para baixo...
#!/bin/ash
ps | grep iperf3 | grep -v grep > /dev/null 2>&1
if [ $? = 0 ]; 
  then /etc/init.d/iperfd stop;
  else /etc/init.d/iperfd start; 
fi
###... até aqui

### para que seja executável
# chmod +x /usr/bin/iperfd-btn  

Por fim, acrescenta-se à configuração do roteador, no arquivo /etc/config/system:

config button
	option button 'wps'
	option action 'pressed'
	option handler '/usr/bin/iperf-btn'

config button
	option button 'wps'
	option action 'released'
	option handler 'logger "mais que 2s e menos que 4s"'
	option max '4'
	option min '1'

config button
	option button 'wps'
	option action 'released'
	option handler 'logger "mais que 5 segundos e menos que 10 segundos"'
	option max '10'
	option min '5' 

# /etc/init.d/system reload

A ação executada pelo hardware é definida pela opção handler. Nesse exemplo, as mensagens de tempo aparecerão no log de sistema a cada vez que o botão for pressionado e solto após X segundos.

Client

Para Android, testei o app Analiti. Basta digitar o hostname/IP e a porta configurada na outra ponta.

Em uma máquina Arch Linux, deve-se instalar o pacote iperf3 e executá-lo em linha de comando.:

# pacman -S iperf3
# iperf3 -p 5005 -c ROUTER_ABOVE
  • -c : Nome ou IP ou dispositivo
  • -p : porta onde o iperf3 está executando remotamente
  • -V : exibir mais informações na tela (verbose)
  • -R : modo reverso, onde o servidor envia dados para cliente (por padrão, cliente -> servidor)
  • -u : usar UDP (por padrão, usa-se TCP)
  • -4 : usar apenas IPv4
  • -6 : usar apenas IPv6