Por dentro do OpenWRT

- por Sergio Prado

Categorias: Linux Tags: , ,

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

openwrt

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

Navegue
Creative Commons Este trabalho de Sergio Prado é licenciado pelo
Creative Commons BY-NC-SA 3.0.