Por dentro do OpenWRT
- por Sergio Prado
Trabalhei um bom tempo na Vex (hoje Oi/Wifi) como gerente da equipe de engenharia. O negócio da empresa era basicamente prover acesso WiFi, e a minha equipe cuidava do firmware que rodava nos roteadores (que na época eram instalados nos principais aeroportos do Brasil, além de várias redes de alimentação famosas como McDonald’s e Fran’s Café).
Como o foco da empresa não era fabricar o hardware, usávamos roteadores de mercado (D-Link, Linksys, Netgear e Asus), e nosso trabalho era embarcar o Linux nestes roteadores. Para esta tarefa, contávamos com a ajuda de uma distribuição Linux chamada OpenWRT.
De acordo com o site do projeto, o OpenWRT é uma distribuição Linux para dispositivos embarcados. Apesar do sistema de build do OpenWRT ser bem flexível, a distribuição criada é bem orientada à sistemas que envolvem comunicação em rede, como roteadores, servidores de arquivo e gateways (veja uma lista completa dos dispositivos de hardware suportados pelo OpenWRT). Por esse motivo, tem sido bastante usado por fabricantes como Atheros, Broadcom e Marvell para liberar BSPs para seus chips.
Como já faz um certo tempo que não trabalho com o OpenWRT, resolvi baixar o código-fonte, fazer alguns testes e documentar aqui o resultado, comentando um pouco também sobre alguns componentes interessantes da distribuição, como o mecanismo de comunicação entre processos chamado ubus e o sistema de configuração UCI.
COMPILANDO O OPENWRT
Antes de compilar o OpenWRT é necessário preparar a máquina de desenvolvimento, no meu caso um Ubuntu 14.04 64 bits:
$ sudo apt-get install build-essential subversion git-core libncurses5-dev zlib1g-dev gawk flex quilt libssl-dev xsltproc libxml-parser-perl mercurial bzr ecj cvs unzip |
O código-fonte do OpenWRT está disponível em um repositório git, e o comando abaixo irá clonar o branch principal de desenvolvimento:
$ git clone git://git.openwrt.org/openwrt.git |
O sistema de build do OpenWRT é baseado no Buildroot, e a interface de configuração pode ser aberta com o famoso menuconfig:
$ make menuconfig |
Para minha surpresa, um dos targets disponíveis é o AM33xx, chip utilizado na Beaglebone Black. Isso significa que poderei testar a distribuição gerada na famosa placa do cachorrinho da TI…:)
Target System (TI OMAP3/4/AM33xx) ---> |
Para compilar, basta mandar um “make” e esperar:
$ make |
No final da compilação, todas as imagens (u-boot, kernel, device tree e rootfs) estarão no diretório bin/omap/:
$ ls -l bin/omap/ total 3628 drwxr-xr-x 2 sprado sprado 4096 Abr 4 15:57 dtbs -rw-r--r-- 1 sprado sprado 123 Abr 4 15:57 md5sums -rw-r--r-- 1 sprado sprado 1715100 Abr 4 15:57 openwrt-omap-Default-rootfs.tar.gz -rwxr-xr-x 1 sprado sprado 1969376 Abr 4 15:57 openwrt-omap-zImage drwxr-xr-x 3 sprado sprado 4096 Abr 4 15:39 packages drwxr-xr-x 2 sprado sprado 4096 Abr 4 15:45 uboot-omap-am335x_evm drwxr-xr-x 2 sprado sprado 4096 Abr 4 15:46 uboot-omap-omap3_beagle drwxr-xr-x 2 sprado sprado 4096 Abr 4 15:46 uboot-omap-omap3_overo drwxr-xr-x 2 sprado sprado 4096 Abr 4 15:47 uboot-omap-omap4_panda |
Então é só gravar as imagens no cartão SD e testar.
Já estava até com saudades da mensagem de saudação exibida no boot do OpenWRT…:)
BusyBox v1.22.1 (2015-04-04 15:51:59 BRT) built-in shell (ash) Enter 'help' for a list of built-in commands. _______ ________ __ | |.-----.-----.-----.| | | |.----.| |_ | - || _ | -__| || | | || _|| _| |_______|| __|_____|__|__||________||__| |____| |__| W I R E L E S S F R E E D O M ----------------------------------------------------- CHAOS CALMER (Bleeding Edge, r45269) ----------------------------------------------------- * 1 1/2 oz Gin Shake with a glassful * 1/4 oz Triple Sec of broken ice and pour * 3/4 oz Lime Juice unstrained into a goblet. * 1 1/2 oz Orange Juice * 1 tsp. Grenadine Syrup ----------------------------------------------------- root@OpenWrt:/# |
ANALISANDO O OPENWRT
Listando os processos em execução em espaço de usuário, podemos ver que a distribuição padrão vem com alguns servidores habilitados, incluindo dhcp, telnet, ntp, dns e ssh.
root@OpenWrt:/# ps | grep -v ]$ PID USER VSZ STAT COMMAND 1 root 1304 S /sbin/procd 677 root 784 S /sbin/ubusd 714 root 1312 S /bin/ash --login 715 root 668 S /sbin/askfirst /bin/ash --login 995 root 940 S /sbin/logd -S 16 1027 root 1388 S /sbin/netifd 1049 root 1072 S /usr/sbin/odhcpd 1106 root 1300 S /usr/sbin/telnetd -F -l /bin/login.sh 1150 root 1304 S /usr/sbin/ntpd -n -S /usr/sbin/ntpd-hotplug -p 0.ope 1187 nobody 864 S /usr/sbin/dnsmasq -C /var/etc/dnsmasq.conf -k -x /va 1269 root 1036 S /usr/sbin/dropbear -F -P /var/run/dropbear.1.pid -p |
O OpenWRT possui algumas funcionalidades interessantes não encontradas em distribuições Linux.
Por exemplo, o procd é a aplicação init do OpenWRT (veja o PID 1 na listagem acima), sendo responsável por gerenciar os processos em execução. Ele também faz o trabalho do udev (gerenciamento dinâmico de dispositivos), klogd e syslogd (daemons de log) e watchdogd. Sim, ele é um “mini” systemd. :-)
O OpenWRT implementa seu próprio mecanismo de comunicação entre processos chamado ubus (micro bus). Ele utiliza UNIX sockets e tem o mesmo objetivo do D-Bus em distribuições Linux e do Binder no Android. É composto pelo daemon ubusd, uma biblioteca de acesso e algumas ferramentas utilitárias.
O comando ubus permite listar todos os namespaces registrados (um namespace é uma espécie de entidade capaz de prover serviços ao sistema via RPC):
# ubus list dhcp log network network.device network.interface network.interface.lan network.interface.loopback network.wireless service system |
Podemos listar os métodos exportados por determinado namespace:
# ubus -v list system 'system' @aab919b4 "board":{} "info":{} "upgrade":{} "watchdog":{"frequency":"Integer","timeout":"Integer","stop":"Boolean"} "signal":{"pid":"Integer","signum":"Integer"} "nandupgrade":{"path":"String"} |
O comando abaixo irá executar o método board do namespace system (o resultado é retornado no formato JSON):
# ubus call system board { "kernel": "3.18.10", "hostname": "OpenWrt", "system": "ARMv7 Processor rev 2 (v7l)", "model": "TI AM335x BeagleBone Black", "release": { "distribution": "OpenWrt", "version": "Bleeding Edge", "revision": "r45269", "codename": "chaos_calmer", "target": "omap\/generic", "description": "OpenWrt Chaos Calmer r45269" } } |
Muitos scripts utilizam este recurso para requisitar o status e configurar o sistema. Veja por exemplo o script /sbin/ifstatus, que utiliza o ubus para se comunicar com o daemon netifd e requisitar o status de uma interface de rede:
#!/bin/sh INTERFACE="$1" [ -n "$INTERFACE" ] || { echo "Usage: $0 " exit 1 } ubus -S list "network.interface.$INTERFACE" >/dev/null || { echo "Interface $INTERFACE not found" exit 1 } ubus call network.interface status "{ \"interface\" : \"$INTERFACE\" }" |
Outro recurso interessante do OpenWRT é o UCI (Unified Configuration Interface) cujo objetivo, como o próprio nome sugere, é centralizar a configuração do sistema. Toda a configuração fica armazenada em arquivos texto no diretório /system/config:
# ls /etc/config/ dhcp dropbear firewall network system |
Uma ferramenta chamada uci permite exibir ou alterar a configuração. Por exemplo, o comando abaixo irá exibir a configuração do sistema:
root@OpenWrt:/# uci show dhcp.@dnsmasq[0]=dnsmasq dhcp.@dnsmasq[0].domainneeded='1' dhcp.@dnsmasq[0].boguspriv='1' dhcp.@dnsmasq[0].filterwin2k='0' dhcp.@dnsmasq[0].localise_queries='1' dhcp.@dnsmasq[0].rebind_protection='1' dhcp.@dnsmasq[0].rebind_localhost='1' dhcp.@dnsmasq[0].local='/lan/' dhcp.@dnsmasq[0].domain='lan' dhcp.@dnsmasq[0].expandhosts='1' [...] |
Podemos também listar determinada configuração, por exemplo a configuração do IP da LAN:
# uci show network.lan.ipaddr network.lan.ipaddr='192.168.1.1' |
Existe uma biblioteca em C para as aplicações poderem acessar estas configurações e uma versão para a web chamada LuCI, permitindo alterar estas configurações via páginas Web através de um servidor HTTP.
Eu gosto muito do OpenWRT. É bom ressaltar que ele não é um sistema de build genérico como o Buildroot ou o Poky (Yocto Project). Ele foi feito basicamente para construir distribuições Linux para sistemas que envolvem de alguma forma ferramentas e serviços de rede. E neste caso pode ser uma ótima opção. É bastante leve, possui uma comunidade ativa, e possui um bom suporte à dispositivos de hardware de mercado.
Com toda essa onda de IoT, o OpenWRT pode se destacar, sendo uma boa solução para o desenvolvimento de gateways, conectando sensores, wearables e outras “coisas” à nuvem.
Um abraço!
Sergio Prado