Discuta este tópico no fórum

Se este conteúdo te ajudou, deixe um presente!

quinta-feira, 29 de outubro de 2015

OpenWRT: nova versão do sane-backends e hplip para OpenWRT

Mais um artigo da série sobre o OpenWRT.

Uma das mudanças da nova versão do OpenWRT é que a política de gerenciamento dos pacotes foi renovada. Agora todos tem um mantenedor. Os pacotes que não ganharam um pai não foram compilados na nova versão. Então, não estranhe se ao atualizar o seu roteador e tentar reinstalar um pacote, um ou outro pacote estiver faltando.


E o que fazer se você queria aquele pacote? Que tal adotá-lo você mesmo? Fui o que fiz para o sane-backends. Este artigo é sobre as melhorias feitas neste pacote que fornece a infraestrutura para acesso a scanners. A configuração para transformar um scanner normal em um scanner de rede já foi tema anterior deste blog.

Um dos grandes problemas que o pacote anterior tinha era a exigência de espaço para instalá-lo. Além de conter todos os drivers, ele dependia do CUPS, que não é lá muito pequeno. O ideal para quem for portar algo para o OpenWRT é tentar isolar os recursos em pequenos pacotes para que o usuário possa instalar somente o que ele vai usar. Não era a situação anterior deste pacote.

O sane-backends era dividido em:
  • sane-backends: continha todos os executáveis (incluindo o daemon) e configurações;
  • sane-libs: tudo que era uma biblioteca, includindo os drivers e a biblioteca base;
  • sane-frontends: clientes simples do sane;
O problema desta estrutura é que ela separa tipo de arquivo (configuração e executáveis, bibliotecas) e não funcionalidades. O sane-libs não vivia sem o sane-backends e todos os backends (drivers) estavam juntos. Para quem fosse usar o hplip (para scanners HP), nenhum backend era usado. Fora este desperdício, ainda temos a dependência ao CUPS (que é relacionado a impressoras e não diretamente a scanners). Então, para usar o scanner no OpenWRT, era quase requisito aumentar o disco com uma unidade externa. Simplesmente não cabia em uma flash de 8MB.

O primeiro passo foi juntar o sane-libs e o sane-backends e dividí-los por funcionalidade. No caso, temos a biblioteca básica (libsane), que todos os clientes e backends usam, o daemon usado para acesso de clientes remotos e os diversos backends, que são compostos de um módulo (implementado como uma biblioteca - extensão .so) e um arquivo de configuração.

Na nova modelagem, o pacote ficou dividido em:
  • libsane: apenas a biblioteca básica do sane, usada por todos os drivers (inclusive o hplip);
  • sane-daemon: inclui apenas o daemon do sane e suas configurações, depende da libsane; 
  • sane-<xxx>: onde <xxx> é um backend. Possui dependência particular de cada pacote;
  • sane-backends-all: metapacote que instala todos os backends;
  • sane-frontends: clientes simples do sane (igual a versão anterior).
Foram feitos alguns patches de melhorias para retirar a dependência do CUPS (era usado somente para localizar um tipo de scanner), reduzir a dependência entre bibliotecas e mais um bom tanto de ajustes relacionados a compilação em arquiteturas diferentes usando uma libc diferente (uclibc e musl). Algumas das correções foram enviadas ao projeto do SANE e já integram atualmente a versão estável do sane!

Resultado? O básico do sane pode ser instalado com algo em torno de 70 Kbytes (fora a dependência da libusb). Esta nova versão proposta estará na nova versão do OpenWRT (DD) ainda em desenvolvimento neste momento. Se quiser usá-la imediatamente em versões anteriores, tenho um repositório próprio com uma seleta de pacotes para algumas arquiteturas em http://luizluca.github.io/openwrt/.

E se eu tenho uma multifuncional HP, como faço com a hplip? Também temos uma nova versão proposta da hplip no repositório que mencionei acima. Este, além de atualizar a versão, o que antes era apenas um pacote foi dividido em:
  • hplip-common: bibliotecas usadas por ambos os próximos pacotes;
  • hplip-sane: backend sane. Se for usar apenas a impressora e não o CUPS no roteador, só vai precisar deste. A impressora ainda pode ser usada sem o driver pelo p910nd;
  • hplip-cups: o driver para o cups. Somente este pacote depende do CUPS.
Mesmo o hplip-sane precisava do CUPS para localizar scanners de rede. Assim como no sane-backends, esta funcionalidade foi removida por um patch para não deixar a dependência. Isto retira uma funcionalidade de buscar scanners em impressoras na rede. Porém, não fazia muito sentido o roteador buscar um scanner que já está na rede para, novamente, disponibilizá-lo na rede. Neste caso, o cliente deve conversar diretamente com a impressora e não utilizar o roteador. O foco do uso do OpenWRT é justamente transformar uma impressora/scanner local em um equipamento de rede.

Todavia, existe ainda uma questão a ser resolvida para as versões CC e DD: ninguém adotou o CUPS. Desta forma, ele não está disponível. Ainda vou ver o que eu posso fazer quanto a isto, se tento eliminar o hplip-cups, adotar o pacote do cups ou esperar que alguém o adote. Provavelmente vou disponibilizar os pacotes do hplip-sane para as novas versões no meu repositório.

Se pintar um problema, tem sempre o fórum deste blog. Até a próxima.

sábado, 3 de outubro de 2015

OpenWRT: Configurando o QoS - Utilizando o SQM

Este é mais um artigo da série sobre o OpenWRT.


O problema de QoS foi tratado em dois posts anteriores. No primeiro, mostrando o problema e no segundo configurando uma solução com o qos-scripts. Este artigo é uma alternativa ao uso do qos-scripts, utilizando o sqm-scripts.

O SQM surgiu do projeto CeroWRT (fork  do OpenWRT), que tem como principal objetivo atacar o excesso de buffer nos equipamentos de rede (o bufferbloat), que geram grandes latências quando o enlace está sobre carga. As melhorias deste projeto retornaram para o OpenWRT (versão BB ou posterior) e para o Linux em geral.

Vamos rever alguns conceitos: podemos avaliar um enlace por três parâmetros:
  • A taxa de transmissão (vulgarmente conhecido como "velocidade");
  • A latência (duração da viagem de um pacote até seu destino);
  • E o jitter (variação na latência).
Contratamos internet sempre pelo primeiro parâmetro (taxa de transmissão) mas dificilmente olhamos os demais. Os "speedtests" focam no primeiro, que é quantos dados você pode receber/enviar em um determinado tempo. Este é o fator determinante de quanto tempo o download de um arquivo vai levar ou se sua conexão vai aguentar assistir aquele filme do Netflix sem engasgar.

Os outros dois parâmetros (latência e jitter) são mais importantes para aplicações "em tempo real", como videoconferência, voz (VoIP), sessão remota (VNC, RDP, etc) e jogos online com interação imediata (FPS, MMORPG, RTS, etc, mas não o poker). A latência determina em quanto tempo o inimigo do Battefield que entrou na sua frente vai aparecer no seu computador e também quanto tempo o seu tiro vai levar para chegar ao servidor. Se a latência for muito grande, até seu tiro chegar ao servidor, seu inimigo mirou na sua cabeça, pensou duas vezes e atirou umas três vez. No "mundo virtual", você estava morto antes de tê-lo visto. Mesmo na navegação Web, a latência importa pois se ela estiver em algo como 1s, um clique em uma página vai levar uns 6 segundos para começar a carregar. É o clássico "a internet está lenta hoje", mas ao baixar um arquivo, a taxa de transmissão não está tão ruim. Já o jitter é a variação deste atraso. Se for significativo, os pacotes começarão a chegar fora de ordem e não serão úteis para aplicações em tempo real. Para minimizar isto, foram criadas filas (buffers) que reorderam os pacotes enquanto aguardam serem enviados. O problema é que atualmente se exagera no tamanho nesta fila, gerando o problema do bufferbloat.

Quando o enlace estiver sobrando, não existem filas e não existe problema. Agora, quando você tem alguém enchendo a fila dos roteadores no seu caminho (que ocorre quando você baixa ou sobe qualquer coisa na velocidade do seu enlace), o excesso de buffer gera uma fila longa e aumenta da latência). Para testar isto, faça um ping a um equipamento fora da sua rede (ex: 8.8.8.8 do google) e inicie um download ou upload (ou ambos) grande para um local que consiga usar toda a sua conexão. A latência do ping irá fatalmente aumentar. Esta diferença no tempo antes e depois do download/upload é um indicativo do tempo que um pacote leva para passar na fila dos seus roteadores. Você também pode fazer isto por alguns provedores de "testes de velocidade", como o http://www.dslreports.com/speedtest (não foque na velocidade ou na latência, que pode ser pequena/grande pela distância, mas no bufferbloat). O ideal seria que a latência mesmo quando o enlace estiver com carga (download ou upload) deveria ser apenas um pouco maior do que a situação quando o enlace está ocioso. Outra forma de testar é pelo script betterspeedtest do projeto CeroWrt. Funciona em qualquer Linux ou de dentro do OpenWRT (basta instalar o netperf).

E como resolver o bufferbloat? Deixe as filas menores para que, quando cheias, novos pacotes sejam descartados, informando ao emissor que ele precisa "pegar leve". Em conjunto, você pode dividir seu tráfego em filas para casos distintos (similar aos caixas-rápidos do supermercado que limitam o atendimento a clientes com até 20 produtos).

No OpenWRT, existem duas propostas para solucionar este problema: o qos-scripts (mais antigo) e o sqm-scripts (mais novo), que trabalham em conjunto com o escalonador de pacotes padrão fq_codel (também focado no problema do bufferbloat). O primeiro faz algumas classificações automáticas (pelo volume de tráfego e alguns sabidamente urgentes) mas deixa a parte pesada da classificação na mão do operador. Já o segundo utiliza inteligência para classificar o tráfego automaticamente, sem parametrização (SQM significa "Smart Queue Management". A inteligência está parte "Smart"). Neste artigo vou tratar de como configurar a segunda proposta.

Tanto para o qos-scripts como para o sqm-scripts, o parâmetro determinante para o seu funcionamento é a taxa de transmissão do enlace. Para controlar a fila, o roteador tem que fazer a fila da conexão fica nele, seja para subir ou descer pacotes. E para a fila ocorrer no roteador, este tem que limitar o tráfego a um valor menor do que a sua conexão com a internet pode aguentar. Assim, não serão feitas filas significativas nos equipamentos da sua provedora de internet, apenas no seu roteador. Por isto, o valor de download/upload configurado deve ser menor do que o contratado. Falam de algo entre 85% a 95% da taxa de transmissão real. Se este parâmetro for maior do que a taxa de transmissão real (real, não a contratada), os controles não atuarão e o QoS não será efetivo.

sqm-scripts e o qos-scripts são mutualmente exclusivos. Se estava usando o qos-scripts e quer usar o sqm-scripts, remova-o antes de iniciar o processo.

A instalação do sqm-scripts é bem simples e parecida com o qos-scripts:

# opkg update
# opkg install sqm-scripts

Se quiser a interface Luci (web):

# opkg install luci-app-sqm

O arquivo de configuração fica em /etc/config/sqm, que pode ser alterado sem problemas pelo Luci em "Rede/SQM Qos". A configuração mínima se limita a:
  1. Habilitar a configuração;
  2. Definir a interface WAN, normalmente eth1 ou eth0.2. Esta pode ser identificada na página de interfaces ou mesmo em "Estado/Visão Geral";
  3. Configurar os valores de download e upload para algo entre 85% a 95% da taxa de transmissão real.
Depois é só habilitar e disparar o serviço sqm pela interface Luci ou pelo SSH:

/etc/init.d/sqm enable
/etc/init.d/sqm start

Feito! Só testar a sua conexão. Para efeitos de testes, eu usei o script betterspeedtest que mencionei acima diretamente no roteador.

Inicialmente, sem o SQM:

root@router.lan3:~# sh betterspeedtest.sh
2015-09-30 01:27:05 Testing against netperf.bufferbloat.net (ipv4) with 5 simultaneous sessions while pinging gstatic.com (60 seconds in each direction)
..............................................................
 Download:  5.14 Mbps
  Latency: (in msec, 62 pings, 0.00% packet loss)
      Min: 16.616
    10pct: 485.537
   Median: 762.117
      Avg: 751.026
    90pct: 963.462
      Max: 970.820
.................................................................
   Upload:  0.63 Mbps
  Latency: (in msec, 62 pings, 0.00% packet loss)
      Min: 10.778
    10pct: 840.844
   Median: 1006.490
      Avg: 971.260
    90pct: 1115.123
      Max: 1151.302

A taxa de transmissão corresponde a contratada (até mais) mas a latência do download/upload, respectivamente, sobe de 16/10 milissegundos em "repouso" para, em média, 762/1006 milissegundos quando em carga. Isto significa que, sobre carga, tudo que dependa de resposta rápida vai "engasgar" em torno de um segundo antes de chegar ao seu destino. E isto é multiplicado para protocolos que exigem negociação/confirmação, como o TCP. Se você já sentiu sua internet lenta quando está anexando um documento grande em um email vai saber do que eu falo.

Agora ativando o SQM:

root@router.lan3:~# sh betterspeedtest.sh 
2015-09-30 01:40:12 Testing against netperf.bufferbloat.net (ipv4) with 5 simultaneous sessions while pinging gstatic.com (60 seconds in each direction)
.............................................................
 Download:  4.61 Mbps
  Latency: (in msec, 61 pings, 0.00% packet loss)
      Min: 10.860 
    10pct: 12.388 
   Median: 18.495 
      Avg: 20.443 
    90pct: 27.702 
      Max: 57.228
..............................................................
   Upload:  0.5 Mbps
  Latency: (in msec, 60 pings, 0.00% packet loss)
      Min: 11.078 
    10pct: 12.813 
   Median: 25.371 
      Avg: 26.920 
    90pct: 42.409 
      Max: 54.265

Agora o aumento na latência foi bem menor! A média subiu apenas para 18/25, respectivamente. Em contrapartida, a taxa de transmissão foi menor pois estou podando ela antes de atingir o limite que a operadora me oferta.

Mas o valor ainda subiu muito! Olhe o valor máximo! O SQM tem um certo volume de carência em função da taxa de transmissão configurada. No início da conexão, ele permite que a fila aumente pois ainda não conhece o comportamento desta conexão. No speedtest pelo navegador que mencionei anteriormente, é possível observar este comportamento. Quando esta apresentar um volume maior, ela vai ser reclassificada. Outro motivo é para aproveitar melhor as rajadas de tráfego (seu provedor, por exemplo, pode liberar uma maior taxa de transmissão para os primeiros kbytes para tornar a resposta de coisas leves como navegação em páginas mais fluída). Se podar ainda mais sua conexão, ou fazer um teste mais longo, a média tende a ser menor.

Brinque, teste variações na configuração na velocidade de upload e download. Avalie quando o QoS se tornou efetivo. Compare com o qos-scripts. Avalie a usabilidade da internet. Compartilhe sua experiência com o sqm-scripts no fórum deste blog.

Até a próxima.

quinta-feira, 1 de outubro de 2015

OpenWRT: Atualizando para versão 15.05

Mais um artigo da série sobre o OpenWRT.

Já temos a Caos Calmer (CC) 15.05. Agora vamos atualizar nossos sistemas!

Sim, este artigo repete diversos pontos do artigo de atualização anterior.

96,72% dos problemas com instalação/atualização com OpenWRT que ajudo é em relação a escolha incorreta da imagem da firmware. Como sempre, recomendo a versão squashfs, que possui modo de recuperação. Pegue o arquivo no download da Caos Calmer e nunca em um endereço qualquer, mesmo que seja na wiki do OpenWRT. Normalmente a wiki referencia a versão em desenvolvimento, que não é a que você quer. No diretório de download, navegue seguindo o caminho da "arquitetura alvo" em uso no seu roteador. Se você já é um usuário do OpenWRT, você pode vê-la olhando o arquivo /etc/openwrt_release:
root@router:~~# cat /etc/openwrt_release
DISTRIB_ID='OpenWrt'
DISTRIB_RELEASE='15.05'
DISTRIB_REVISION='r46767'
DISTRIB_CODENAME='chaos_calmer'
DISTRIB_TARGET='ar71xx/generic'
DISTRIB_DESCRIPTION='OpenWrt Chaos Calmer 15.05'
DISTRIB_TAINTS=''
A diferença entre a primeira instalação e a atualização é que não será usada a imagem "factory" e sim a "sysupgrade". Escolha o arquivo correspondente ao seu roteador (inclusive versão de hardware!). E muito importante, leia a wiki do seu roteador independente se ele já funcionava na versão anterior! São poucos minutos de leitura que podem salvar horas de trabalho ou mesmo seu roteador.

Bem, se eu simplesmente ir na interface, fornecer a nova imagem, ele vai funcionar? Provavelmente, mas talvez não é a maneira que dê menos trabalho. A atualização pode preservar as configurações mas não os programas instalados. Se você tem raiz expandida em unidade externa, a encrenca é ainda maior.

Mas eu nunca instalei um programa! OK, use a interface web e provavelmente todas as configurações serão migradas sem problemas. Já testei isto em mais de um roteador e funcionou sem problemas. Mas faça o backup antes! Caso tenha instalado algum pacote, continue lendo.

Em primeiro lugar, precisamos do plano de retorno caso a nova versão não se comporte como o esperado. Faça sempre um backup geral do seu sistema. No processo de upgrade, eu sugiro que sejam feitas as três formas diferentes de backup que eu comento no artigo sobre o temabackup gerado pelo openwrt, lista de pacotes instalados e todos os arquivos do overlay. Este último serve apenas para o plano de retorno caso algo importante não funcione para você na nova versão.

Agora, finalmente, você está pronto para enviar a nova firmware. Se você usa um armazenamento externo para expandir a raiz, leia até o final deste post antes de iniciar o processo! Faça o upgrade pela interface web ou pelo terminal. Inclusive, você pode baixar o arquivo diretamente no roteador. Ex:

# cd /tmp
# wget http://downloads.openwrt.org/chaos_calmer/15.05/.../openwrt-15.05-...-squashfs-sysupgrade.bin
# sysupgrade openwrt...xxx....img 

Só cuidado ao colar a URL. O downloads.openwrt.org usa https por padrão mas o wget do OpenWRT não tem suporte para https (por padrão). Contudo, o downloads.openwrt.org aceita http sem problemas, só tirar o "s".

E pode fazer pela Wifi? Os fabricantes não recomendam usar sempre um computador "conectado por cabo"? Sim, e já tive problemas com atualização por não escutar isto. Mas não com OpenWRT. Se estiver atualizando (e não instalando a primeira vez!), pode fazer pela Wifi sem problemas. Quando a gravação for iniciada, todo o processo já está independente do computador cliente.

E depois do "Enter"/"Gravar", é a hora que você reza. Sempre dá um frio na barriga.

Se optar por preservar as configurações, tudo que seria guardado em um backup do sistema (listado pelo "sysupgrade -l") será restaurado. Se você instalou algum pacote e guardou a lista do que foi instalado, esta é a hora que você reinstala os pacotes desejados. Se for instalar manualmente, procure instalar os pacotes de mais alto nível (ex: "luci-app-minidlna" antes de "minidlna"), pois eles irão, por dependência, baixar os pacotes requeridos. No final do processo, é bom refazer a listagem do que está instalado e comparar com o que você tinha na versão anterior.

Não é comum no OpenWRT mas pode existir alguma atualização de segurança importante, como ocorreu com o Heartbleed. De qualquer forma, é bom listar os pacotes atualizáveis:

# opkg update
# opkg list-upgradable

O maior problema é que estas atualizações de segurança também ocupararão espaço a mais do seu roteador (overlay) pois apagar ou substituir arquivos existentes na firmware inicial não recupera o espaço usado no sistema de arquivos.

Por fim, faça um novo backup geral. É sempre bom preservar o seu trabalho.

Se precisar retornar a versão anterior do OpenWRT, realize a gravação da firmware antiga, entre no modo de recuperação e restaure a overlay.

Se você não usa uma unidade externa para expandir o espaço interno, seu trabalho acabou. Para os demais, o processo é um pouco mais complicado... Ao atualizar o sistema, você terá um kernel novo que é incompatível com os módulos de kernel existentes na unidade externa ou mesmo com as bibliotecas pertencentes à versão anterior. Você precisaria reinstalá-los. Esta é a sugestão de como proceder:

Em primeiro lugar, gere todos os backups sugeridos anteriormente. É importante preservar seu trabalho anterior. Ainda sem instalar a nova firmware, reinicie o sistema sem a unidade externa. Se você seguiu minha sugestão de manter uma configuração básica na flash interna, você ainda terá um ambiente funcional. Com isto, ele vai usar somente a flash interna (com a configuração que você tinha antes de usar a unidade externa).

Ainda com a unidade externa desconectada, faça o procedimento de atualização descrito neste artigo para quem não usa raiz expandida, inclusive com a etapa de backups. Você terá que preservar os dois conjuntos de backups: com e sem a unidade externa em uso. Ao final do processo, você deverá ter a sua configuração básica restabelecida. Caso tenha optado por não preservar as configurações na gravação, você pode aproveitar o backup gerado quando a unidade externa estava desconectada (o segundo) para restaurar as configurações.

Neste momento, a unidade externa ainda está com os programas da versão anterior, que são geralmente incompatíveis com a nova versão (os módulos de kernel sempre o são). Por isto, precisamos nos livrar de todos os arquivos da versão anterior do OpenWRT presentes na unidade externa. Na unidade externa, na partição usada como overlay, remova todo o conteúdo ou mova tudo para um subdiretório (ou para outra unidade se não estiver com espaço livre) afim de que este não seja usado. Como sugestão, crie um "openwrt-versao-xxx" e mova tudo para lá. Refaça a configuração de uso de uma unidade externa (que no mínimo será reinstalar os pacotes necessários). Reinicie o sistema. Você deve estar agora com mais espaço na raiz.

Neste ponto, você ainda terá as mesmas configurações que tinha quando usou o sistema sem a unidade externa. Envie o primeiro backup da versão anterior feito com a unidade externa conectada (primeiro backup). Na sequência, reinstale os pacotes extras, assim como é feito para ambientes sem a raiz expandida. Complete o trabalho com aquele backup final.

Espero que apreciem a nova versão. De agora em diante, vou apenas focar em configurações específicas do 15.05, que ainda podem funcionar nas versões 14.07, 12.09 e 10.03.1.

Se pintar um problema, tem sempre o fórum deste blog. Até a próxima.

terça-feira, 29 de setembro de 2015

OpenWRT: Fazendo Backups

Mais um artigo da série sobre o OpenWRT.

Antes de comentar como atualizar para a próxima versão do OpenWRT, achei interessante comentar sobre um assunto relacionado, mas tão importante que merece um artigo próprio: backups.

Tem gente que ainda confia em tecnologia. Brinco dizendo que não adianta rezar, só backup salva. Depois de fotos, vídeos, documentos, os roteadores são a última coisa que as pessoas se preocupam em fazer backup. Afinal de contas, para os mais simples, ele só contém o nome da rede e a senha. Porém, com o OpenWRT, seu roteador pode ser muito mais do que isto. O meu, em especial, é a central de comunicação, entreterimento e armazenamento da casa. Na prática, um servidor na rede com múltiplas funções. Como configurá-lo exige uma significativa quantidade de trabalho, sempre é bom evitar que você tenha que refazê-lo caso algo aconteça com ele.

Saindo do ambiente residencial, o tempo de restauração normalmente é crítico para ambientes empresariais. Neste caso, um backup "na mão" facilita em muito restaurar rapidamente um equipamento com defeito. Fora isto, backup podem ser utilizados para replicação "em massa", evitando o retrabalho de configurar o roteador "do zero" (para este fim, tem que recriar a entrada da ULA do IPv6).

Neste artigo, vou considerar que você conhece um básico do OpenWRT, como a estrutura que usa o squashfs com a overlay.

O OpenWRT tem backup? Sim, mas não de tudo. O backup do OpenWRT guarda somente configurações e dados selecionados do /etc. A lista do que ele copia pode ser vista com o comando "sysupgrade -l":
root@router:~~# sysupgrade -l
/etc/config/dhcp
...
/etc/sysctl.conf
/etc/sysupgrade.conf
São alguns arquivos pré-definidos, listados em /lib/upgrade/keep.d/ (pelos pacotes) ou em /etc/sysupgrade.conf, pelo usuário. Programas instalados não serão salvos, mas somente suas configurações (se estiverem em /etc/config ou forem explicitadas pelo mantenedor do pacote). É isto que é preservado quando você faz uma atualização do OpenWRT e pede para salvar as configurações. Compare isto com o conteúdo da overlay. Tudo que estiver lá foi modificado no seu sistema desde a instalação. O que estiver lá e não na listagem do sysupgrade, será perdido utilizando esta forma de backup. 

E quanto aos programas? Se você usa a firmware no formato squashfs, existem duas opções. A primeira é guardar a lista dos pacotes instalados e reinstalá-los. Para facilitar, você pode ver na /overlay:

root@router:~# ls /overlay/usr/lib/opkg/info/*control | sed -e 's%.*/%%;s/\.control//' | xargs

aiccu bind-dig bind-host bind-libs binutils block-mount coreutils-du coreutils ddns-scripts diffutils e2fsprogs...

Com a lista de pacotes salva, basta instalá-los após a restauração da configuração.

A segunda opção é guardar toda a overlay. Para salvar tudo mesmo que você fez desde a instalação do OpenWRT, é bom copiar a partição overlay. Um tar simples pode fazer o serviço. De um computador com Linux, execute:

$ ssh root@router tar -czv /overlay | dd of=backup-roteador.20150925.tgz

Isto compacta a /overlay em um tar e envia para o arquivo local backup-roteador.20150925.tgz sem criar o arquivo no roteador, que nem sempre tem espaço para isto. O WinSCP poderia copiar a overlay mas provavelmente você teria problemas com a permissão (perdida) dos arquivos. Se a overlay for pequena, você pode fazer o tar no /tmp (memória RAM) e copiar com o WinSCP:

root@router:~# tar -czvf /tmp/backup-roteador.20150925.tgz /overlay

Caso use Linux, fiz um pequeno script que faz a cópia do backup do OpenWRT, da lista de pacotes e da overlay em um único passo. Se seu roteador está em 192.168.1.1, só chamar:

$ ./fullbackup 192.168.1.1

E se eu não uso a firmware em squashfs? Primeiro você é corajoso pois se fizer algo de errado, não terá como usar a recuperação do OpenWRT. Contudo, isto não é um problema se o OpenWRT foi instalado em um PC ou VM. Para estes casos, faça o tar de todo o conteúdo. Só precisa tomar o cuidado de excluir os diretórios de dados voláteis (/proc, /sys, /tmp, /var/tmp, ...) ou simplesmente use a opção "--one-file-system" do tar para não sair da partição raíz.

E para restaurar tudo isto? Se for o backup do OpenWRT, pode ser feito pela interface web ou pelo comando sysupgrade. Se for pela overlay, recomendo entrar no modo de recuperação, zerar o roteador, montar a overlay e descompactar o conteúdo diretamente sobre a partição. Escrever na overlay enquanto ela estiver usada resulta em comportamentos incertos.

E, reforçando, não adianta rezar: só backup salva!

Se pintar um problema, tem sempre o fórum deste blog. Até a próxima.

sexta-feira, 25 de setembro de 2015

OpenWRT: Lançamento da versão 15.05 Caos Calmer (CC)

Mais um artigo da série sobre o OpenWRT.

Salve a todos! Depois de um ano de desenvolvimento, finalmente foi lançada uma nova versão estável do OpenWRT. É a Caos Calmer (CC), com o número 15.05.

E o que temos de novo? Que "caos" que esta versão venho acalmar? A grande mudança nesta versão é que o repositório de pacotes foi renovado. O OpenWRT estava dividido em duas grandes partes: o núcleo principal, com a base do OpenWRT e pacotes indispensáveis para seu funcionamento e uma segunda parte com os pacotes "extra". O núcleo principal era e é cuidado com cautela, com o acesso de escrita bem restrito. Contudo, o repositório de pacotes ficava em segundo plano. Pela grande quantidade de pacotes, eles normalmente eram mantidos por pessoas não diretamente ligadas ao desenvolvimento principal do OpenWRT. Normalmente elas montavam o pacote, ele era aceito no repositório e depois ninguém aparecia para dar manutenção e atualizar o pacote. Fora isto, era comum que contriuições enviadas por voluntários nunca serem apreciadas e se perdiam no tempo. Como os pacotes não tinham pai, ninguém tomava a iniciativa de aceitar a contribuição.

Para resolver este dilema, já na versão anterior (BB) foi criado um repositório no github para substituir o packages antigo. Neste, todos os pacotes tem necessariamente que possuir um mantenedor.  As contribuições são enviadas por "Pull Request" (PR), facilitando em muito o controle destas alterações e a contribuição de pessoas não diretamente ligadas ao projeto. Pacotes adotados eram importados neste repositório e removidos do antigo (renomeado para oldpackages). Na versão anterior do BB, isto não foi muito sentido pois o oldpackages foi compilado junto com o novo repositório. Com o lançamento do CC, isto não ocorre mais. Se um pacote não foi adotado, ele estará ausente na versão atual. Resumindo, temos uma menor oferta de pacotes mas com uma qualidade muito superior e com atualizações mais frequentes.

Sentiu falta de um pacote? Você pode ir pelo caminho "Faça você mesmo" e, inclusive, contribuir com a melhoria para o projeto.

Fora esta mudança nos pacotes, como sempre, ocorreram as melhorias de desempenho, correção de bugs e novas funcionalidades vindas das atualizações de versões dos componentes do sistema. Para os usuários normais, podem se destacar:
  • Suporte a protocolos de escalonamento de pacotes que evitam o Bufferbloat, reduzindo a lentidão (latência) quando sua internet estiver sobrecarregada;
  • Melhor desempenho do firewall (novamente menor latência);
  • Maior segurança, com o uso de DNSSEC, opções de hardening na compilação e assinatura de pacotes.

Enfim, temos uma bela versão de firmware para seu roteador, mais rápida, segura e com mais recursos (exceto pelo menor número de pacotes).

No próximo artigo, dicas sobre como atualizar. Até mais.

quinta-feira, 2 de abril de 2015

OpenWRT: Criando novos pacotes - construção de um pacote

Mais um artigo da série sobre o OpenWRT.
 artigo anterior, apresentei o problema da compilação de um novo programa para o OpenWRT. Neste vamos colocar a mão na massa.


Vou pegar um exemplo simples: o figlet. Ele faz isto:

$ figlet LuizLuca
 _          _     _                    
| |   _   _(_)___| |   _   _  ___ __ _ 
| |  | | | | |_  / |  | | | |/ __/ _` |
| |__| |_| | |/ /| |__| |_| | (_| (_| |
|_____\__,_|_/___|_____\__,_|\___\__,_|
                                       

Fantástico, não é? (nem sei como vivi sem ele até hoje) O que o programa faz não importa neste caso.

Você tem duas opções para montar o ambiente para gerar seus pacotes: recompilar todo o OpenWRT ou utilizar o SDK disponível no mesmo local onde estão as firmwares. O primeiro caso vai utilizar mais espaço e demorar mais mas traz a vantagem de isolar problemas do seu ambiente de problemas do seu pacote. Afinal de contas, se compilou todo o OpenWRT e não o meu pacote, o problema provavelmente é comigo. Fora isto, os fontes locais podem facilitar o uso destes como inspiração ou modelo para seu próprio pacote. Problemas de compilação cruzada se repetem aos montes e espiar o vizinho ajuda muito. Também, se seu desejo é integrar o pacote de volta ao OpenWRT para que outros usuários também possam aproveitar seu trabalho, o ideal é trabalhar em conjunto com todo o OpenWRT. 
A segunda opção é mais econômica. Serve mais para compilações isoladas. Como é o caso deste exemplo, foi optar por esta alternativa.

Vou pegar a família ar71xx, muito comum em roteadores, para este exemplo. O SDK desta família está aqui. Baixe de descompacte:

$ wget https://downloads...OpenWRT-SDK-ar71xx-for-linux-...tar.bz2
$ tar -xjvf OpenWRT-SDK...tar.bz2
$ cd OpenWrt-SDK-...

Tem um problema nesta versão do SDK. Ele está com o uso do ccache ativado. Caso isto seja um problema para você, desative-o editando o arquivo Config-build.in nesta parte:

config CCACHE
    bool
    default n

Estamos prontos para criar o primeiro pacote. crie um subdiretório em package. No caso, criarei o figlet (OpenWrt-SDK-.../package/figlet/. Dentro deste criaremos um arquivo Makefile descrevendo o pacote. Makefile? Mas isto não é usado depois na compilação? Sim, o OpenWRT (ab)usou o make para montar todo seu ambiente de compilação. Este Makefile não é o mesmo gerado pelo ./configure mas um padrão do OpenWRT que descreve as informações do seu pacote, como compilar, instalar e metainformações, assim como ocorre nos arquivos spec do RPM. Sim, pode ser feio, nem lembra um Makefile comum, mas funciona. Fora o Makefile existem outros arquivos opcionais. Abaixo do subdiretório "patches" ficam eventuais correções para consertar ou adaptar problemas nos fontes do programa. Caso necessite adicionar algum arquivo não gerado pelo ou presente nos fontes, como scripts de disparo de serviços, estes podem ficam em um outro subdiretório "files". E os fontes? Isto o OpenWRT baixa para você. Você só precisa dizer de onde no Makefile.

O arquivo Makefile do exemplo deste artigo ficaria em package/figlet/Makefile. Inicialmente é assim (em destaque o que alterei):

#
# Copyright (C) 2017 Luiz Angelo Daros de Luca
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#

include $(TOPDIR)/rules.mk

PKG_NAME:=figlet
PKG_VERSION:=2.2.5
PKG_RELEASE:=1
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=ftp://ftp.figlet.org/pub/figlet/program/unix/
PKG_MD5SUM:=d88cb33a14f1469fff975d021ae2858e
PKG_MAINTAINER:=Luiz Angelo Daros de Luca <luizluca@gmail.com>
PKG_LICENSE:=BSD-3-Clause
PKG_LICENSE_FILES:=LICENSE
PKG_INSTALL:=1

include $(INCLUDE_DIR)/package.mk

define Package/figlet
  SECTION:=xxx
  CATEGORY:=Utilities
  TITLE:=FIGlet
  URL:=http://www.figlet.org/
  MAINTAINER:=Claudio Matsuoka <cmatsuoka@gmail.com>
  DEPENDS:=
endef

define Package/figlet/description
  FIGlet is a program for making large letters out of ordinary text
endef

# Eh obrigatorio ser tabs antes das linhas abaixo
define Package/figlet/install
 $(INSTALL_DIR) $(1)/usr/bin
 $(CP) $(PKG_INSTALL_DIR)/usr/bin/* $(1)/usr/bin
 $(INSTALL_DIR) $(1)/usr/share/figlet/
 $(CP) $(PKG_INSTALL_DIR)/usr/share/figlet/* $(1)/usr/share/figlet/
endef

$(eval $(call BuildPackage,figlet))

O cabeçalho do arquivo, comentado, é meramente informativo. Os PKG_* descrevem dados para os pacotes gerados por este Makefile (sim, pode ser mais de um mas não é o caso deste exemplo). Os nomes são bem auto-explicativos. NAME é o nome do pacote, VERSION (do programa) e RELEASE (do pacote), em conjunto, formarão a versão do pacote. SOURCE_URL/SOURCE indicam de onde baixar e o MD5SUM o hash do arquivo. O campo MAINTAINER é o "dono" deste pacote. O PKG_INSTALL pede para que o "make install" seja executado após a compilação.

O "define Package/figlet" efetivamente declara o pacote. Em especial, observe o campo DEPENDS, que possui uma sintaxe própria e é usado para definir as dependências entre os pacotes. Este pacote de exemplo não tem dependências conhecidas (até este momento). "Package/figlet/description" é apenas um texto descritivo.

A compilação ocorre em uma série de etapas.
  • Build/Prepare:  descompacta os fontes, e aplica os patches (Build/Patches)
  • Build/Configure: roda o ./configure (ou equivalente)
  • Build/Compile: roda o make
  • Build/Install: se PKG_INSTALL for 1, roda o "make install", instalando em $(PKG_INSTALL_DIR)
Normalmente você não irá querer mudar essas etapas. Se não definidas, elas irão utilizar um valor padrão, de uma macro com o mesmo nome e sufixo /Default, que normalmente funcionará. Ex: se Build/Prepare não existir no pacote, será utilizado o Build/Prepare/Default. Você tem liberdade de mudar qualquer coisa dessas etapas, chamando ou não o respectivo valor /Default. Porém, normalmente os ajustes necessários são feitos mudando as variáveis usadas (ex: CONFIGURE_ARGS). Se quiser ver o conteúdo, olhe em https://github.com/openwrt/openwrt/blob/master/include/package-defaults.mk.

O "define Package/figlet/install" é um passo importante. Ele preenche a árvore que formará os arquivos do pacote. Este caminho é passado como argumento $(1). Então, se criar um $(1)/usr/yyy, o pacote será o conteúdo /usr/yyy. Normalmente o Package/xxx/install é uma sequência de chamadas ao comando install, que é equivalente uma composição dos comandos mkdir, cp, chmod, chown. Se o "make install" foi utilizado, o Package/xxx/install irá copiar arquivos de $(PKG_INSTALL_DIR) para $(1). Ao invés de usar diretamente o comando install ou ainda o cp/mkdir, o recomendado é utilizar o INSTALL_DIR, INSTALL_BIN, INSTALL_CONFIG, INSTALL_DATA (definidos em https://github.com/openwrt/openwrt/blob/master/rules.mk#L257)

E vamos a compilação:

$ make
Collecting package info: done
#
# configuration written to .config
#
 make[1] world
 make[2] package/compile
 make[3] -C package/figlet compile
make -r world: build failed. Please re-run make with V=s to see what's going on

Erro?! Mas o que aconteceu? O OpenWRT não mostra o erro por padrão. Como sugerido, rode novamente com o V=s para ver o que está acontecendo (vou omitir linhas não relevantes):

$ make V=s
...
mips-openwrt-linux-uclibc-ld  -o figlet figlet.o zipio.o crc.o inflate.o utf8.o
mips-openwrt-linux-uclibc-ld: warning: cannot find entry symbol __start; defaulting to 00000000004000b0
figlet.o:OpenWrt-SDK-ar71xx-for-linux-x86_64-gcc-4.8-linaro_uClibc-0.9.33.2/build_dir/target-mips_34kc_uClibc-0.9.33.2/figlet-2.2.5/figlet.c:293: undefined reference to `stderr'
figlet.o:OpenWrt-SDK-ar71xx-for-linux-x86_64-gcc-4.8-linaro_uClibc-0.9.33.2/build_dir/target-mips_34kc_uClibc-0.9.33.2/figlet-2.2.5/figlet.c:293: undefined reference to `stderr'
figlet.o:OpenWrt-SDK-ar71xx-for-linux-x86_64-gcc-4.8-linaro_uClibc-0.9.33.2/build_dir/target-mips_34kc_uClibc-0.9.33.2/figlet-2.2.5/figlet.c:293: undefined reference to `fprintf'
...

Não achando stderr? fprintf? __start? Isto é da libc! Quem já programou um pouco de C sabe que normalmente não precisamos indicar manualmente a libc para o ligador (linker). E por que ele não achou, então? Bem, o figlet é um dos exemplos onde o desenvolvedor optou por não usar o ./configure (autoconf). Ele escreveu o Makefile manualmente. O problema é que algumas coisas são classicamente configuradas no configure, como o prefixo do programa e parâmetros do compilador e do ligador. Outro problema é assumir coisas que nem sempre são verdades. O problema acima, por exemplo, ocorre porque o ligador (ld) não está ligando a libc ao programa caso isto não seja solicitado explicitamente. E por que funciona para o desenvolvedor? Como ele não viu isto? Na maioria dos casos, o ld disponível no Linux adiciona a libc por padrão e não é necessário explicitá-la. No caso do OpenWRT, o linker não faz isto. Se usasse o ./configure, provavelmente o ligador seria configurado apropiadamente (adicionando a libc). Como já enfrentei este problema anteriormente, conheço uma solução de contorno: usar o gcc como ligador. Isto pode ser feito substituindo a variável ambiente LD do make pelo compilador do alvo. Só adicionar isto ao Makefile anterior:

MAKE_FLAGS += \
    LD="$(TARGET_CC)"

E compilar novamente:

$ make V=s
...
cp figlet chkfont figlist showfigfonts /home/luizluca/Downloads/OpenWrt-SDK-ar71xx-for-linux-x86_64-gcc-4.8-linaro_uClibc-0.9.33.2/build_dir/target-mips_34kc_uClibc-0.9.33.2/figlet-2.2.5/ipkg-install/usr/local/bin
...
cp: cannot stat '/home/luizluca/Downloads/OpenWrt-SDK-ar71xx-for-linux-x86_64-gcc-4.8-linaro_uClibc-0.9.33.2/build_dir/target-mips_34kc_uClibc-0.9.33.2/figlet-2.2.5/ipkg-install/usr/bin/*': No such file or directory

Erro novamente?! Ao menos ele compilou. Por que ele não achou os arquivos? Porque ele instalou o figlet abaixo de /usr/local e não de /usr, como é o padrão do OpenWRT (e da maioria das distribuições). Esta configuração do prefixo é, na maioria dos casos, configurada pelo script ./configure. Se quisesse, poderia alterar o nosso Makefile para usar o /usr/local. Porém, este não é o caminho padrão para este tipo de arquivo. Novamente, a opção por criar manualmente o Makefile prejudicou a compilação cruzada. Caso usasse o ./configure, o OpenWRT iria definir o prefixo automaticamente. Solução? A mesma usada anteriormente: outra variável ambiente para reconfigurar o Makefile do figlet.

MAKE_FLAGS += \
    LD="$(TARGET_CC)" \
    prefix="$(CONFIGURE_PREFIX)"

E agora sim:

$ make
Collecting package info: done
#
# configuration written to .config
#
 make[1] world
 make[2] package/compile
 make[3] -C package/figlet compile
 make[2] package/index

Sucesso! Seu pacote estará em bin/ar71xx/packages/base/figlet_2.2.5-1_ar71xx.ipk.

Copiando para um roteador e instalado. Não é que ele funciona?

$ scp bin/ar71xx/packages/base/figlet_2.2.5-1_ar71xx.ipk root@router:/tmp 
$ ssh root@router
root@router:~# opkg install /tmp/figlet_2.2.5-1_ar71xx.ipk 
Installing figlet (2.2.5-1) to root...
Configuring figlet.
root@router:~# figlet "Funciona!"
 _____                 _                   _ 
|  ___|   _ _ __   ___(_) ___  _ __   __ _| |
| |_ | | | | '_ \ / __| |/ _ \| '_ \ / _` | |
|  _|| |_| | | | | (__| | (_) | | | | (_| |_|
|_|   \__,_|_| |_|\___|_|\___/|_| |_|\__,_(_)
                                             

O Makefile final ficou:


#
# Copyright (C) 2017 Luiz Angelo Daros de Luca
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#

include $(TOPDIR)/rules.mk

PKG_NAME:=figlet
PKG_VERSION:=2.2.5
PKG_RELEASE:=1
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=ftp://ftp.figlet.org/pub/figlet/program/unix/
PKG_MD5SUM:=d88cb33a14f1469fff975d021ae2858e
PKG_MAINTAINER:=Luiz Angelo Daros de Luca <luizluca@gmail.com>
PKG_LICENSE:=BSD-3-Clause
PKG_LICENSE_FILES:=LICENSE
PKG_INSTALL:=1

include $(INCLUDE_DIR)/package.mk

MAKE_FLAGS += \
   LD="$(TARGET_CC)" \
   prefix="$(CONFIGURE_PREFIX)"

define Package/figlet
 SECTION:=xxx
 CATEGORY:=Utilities
 TITLE:=FIGlet
 URL:=http://www.figlet.org/
 MAINTAINER:=Claudio Matsuoka <cmatsuoka@gmail.com>
 DEPENDS:=
endef

define Package/figlet/description
 FIGlet is a program for making large letters out of ordinary text
endef

# Eh obrigatorio ser tabs antes das linhas abaixo
define Package/figlet/install
   $(INSTALL_DIR) $(1)/usr/bin
   $(CP) $(PKG_INSTALL_DIR)/usr/bin/* $(1)/usr/bin
   $(INSTALL_DIR) $(1)/usr/share/figlet/
   $(CP) $(PKG_INSTALL_DIR)/usr/share/figlet/* $(1)/usr/share/figlet/
endef

$(eval $(call BuildPackage,figle
t))


Nem sempre preparar um pacote de algo mais simples será mais fácil. Às vezes, a simplificação do programa pode levar o desenvolvedor a não utilizar práticas padrão de desenvolvimento. Nem cheguei a tratar dependências de bibliotecas. Quando o programa fonte é bem feito, normalmente é questão de adicionar a biblioteca necessária na lista de dependências e pronto. O OpenWRT, inclusive, verifica automaticamente se você não esqueceu de uma delas.

Se fizer algo interessante para o OpenWRT e quiser compartilhar, o desenvolvimento dos pacotes "extras" do OpenWRT está bem produtivo. Ele migrou para https://github.com/openwrt/packages.

Se precisar de uma ajuda, crie um tópico no fórum do blog ou no tópico deste artigo.
Até a próxima.

Atualização em 2017-05-11: adicionado informações sobre etapas de compilação e mais informação sobre o Package/xxx/install; Adicionado o PKG_INSTALL para evitar chamada dentro  do Package/xxx/install.