Fazer o boot do Raspberry pela rede me trouxe saudades.
Em 2005 trabalhava como sysadmin em uma empresa espanhola, mas outras tarefas me eram delegadas. Ajudar a equipe de suporte era uma delas, quando não tinham uma solução para um problema. Na época, instalações de sistemas em mais de 3.000 computadores eram feitas periodicamente utilizando o Norton Ghost com boot pelo disquete. Então, dois operadores eram necessários para liberar a gravação do sistema, pois o servidor ficava em um andar e os computadores a receber a imagem, em diversos andares. Como achei o processo muito burro, idealizei o Phantom; um sistema que iniciou de uma remasterização do knoppix, passou aos moldes de embarcado (com a ajuda do mestre Marcelo Barros) e finalizou seus dias (lá pra 2011) com 14MB e uma interface gráfica feita em Qt. Era um grande sistema, que contava com boot por CD, pendrive, HD externo e boot pela rede. Tinha muitas outras características, mas o artigo não é sobre ele.
Tópicos
- 1 Características de boot por PXE no Raspberry
- 2 Configuração do OTP
- 3 Como pegar o serial do Raspberry Pi
- 4 Setup do servidor TFTP / PXE
- 5 Como o Raspberry saberá onde buscar o sistema de arquivos?
- 6 Onde comprar Raspberry?
- 7 Vídeo
Características de boot por PXE no Raspberry
Primeiro, o boot pela rede só é suportado via cabo, utilizando PXE. A ROM procede inicializando o dispositivo ethernet, enviando uma requisição DHCP e, após receber a resposta, segue com o processo advindo do DHCP, que define os caminhos a seguir. Vou deixar claro no decorrer do artigo.
Configuração do OTP
Verifique previamente se já não está suportado por padrão em seu Raspberry, assim não será necessário sequer fazer a modificação a seguir.
Pra começar, precisamos fazer a primeira configuração da OTP. Para isso, adicionamos ao final do arquivo /boot/config.txt o parâmetro program_usb_boot_mode=1 . Depois de um boot do sistema com essa definição, podemos ler o OTP com o vcgencmd (comando do qual discorri amplamente nesse outro artigo).
vcgencmd otp_dump|egrep '^17:'
O resultado deve ser esse:
Agora já pode desligar o sistema e remover o SD.
Antes de religar o Raspberry, conecte o cabo ethernet. Quando ligado, deve levar um tempo aproximado de 10 segundos para haver manifestação na rede.
Pode ser necessário em algum momento depurar a comunicação para ver como está acontecendo o handshake, ainda que seja apenas para fins didáticos. Nesse caso, recomendo a leitura desse tutorial (muito bem elaborado, por sinal). De qualquer modo, será necessário analisar se está ocorrendo a comunicação, portanto, instale o programa tcpdump:
sudo su apt-get update apt-get install -y tcpdump
Um comando inicial poderia ser:
tcpdump -i eth0 -vvv -XX -s9182 port bootpc
Se estiver usando Ubuntu com o novo esquema (podre) de nome de interface, deve ser algo como enp2s0 no lugar de eth0. Para confirmar, preceda o comando anterior identificando sua interface:
ifconfig
Se não tiver o comando ifconfig em sua distribuição Linux (outra mudança podre e inútil), tem duas opções: instale o pacote net-tools para ter o comando ifconfig, ou use o comando ip. No primeiro caso:
sudo apt-get update sudo apt-get install -y net-tools
E no caso do comando ip:
ip addr show
A saída será numerada e, tirando a interface de loopback (lo) e a WiFi (wlp3s0, wlan0 ou algo do tipo), deve sobrar a interface ethernet.
Usando o comando tcpdump citado mais acima, o resultado deve ser algo como:
Como pegar o serial do Raspberry Pi
Cada Raspberry tem um serial único, que pode ser pego com o comando vcgencmd ou direto no arquivo /proc/cpuinfo, gerado pelo kernel. Para pegar o (número) serial pelo arquivo cpuinfo, faça login no Raspberry e use:
cat /proc/cpuinfo | grep Serial | cut -d ' ' -f 2
E para pegar o (número) serial pelo comando vcgencmd, utilize:
vcgencmd otp_dump|egrep '^28'|cut -f2 -d:
Se quiser saber mais sobre o comando vcgencmd, recomendo o tutorial mais elaborado, exclusivamente sobre os recursos do comando vcgencmd. Se quiser saber em detalhes o significado dos bits do OTP, recomendo a documentação oficial do Raspberry.
Enfim, separe o valor do serial, pois utilizaremos mais adiante. Também vamos precisar do MAC address. Tendo identificado o nome da interface, use o comando a seguir. No Raspberry a interface ainda está com o nome eth0, então:
ifconfig eth0|egrep ether|awk '{print $2}'
O resultado deve ser algo como:
Agora podemos iniciar o processo de configuração.
Setup do servidor TFTP / PXE
Antigamente a única opção era configurar um servidor DHCP e um PXE para fazer a transação com o TFTP. Na época atual temos uma opção que poupa um monte de trabalho, da qual discorro mais adiante.
Instalação de pacotes
Nesse primeiro momento, vamos focar na instalação dos pacotes:
sudo apt-get install -y nfs-kernel-server dnsmasq kpartx
Cópia do sistema de arquivos e boot para o servidor
O Raspberry não tem uma BIOS ou algo do tipo. Quando ligada, simplesmente busca o ponteiro para inicialização em um ou mais lugares, dependendo da versão da placa. Primeiramente, busca pelo inicializador em /boot, no micro SD. No caso da Raspberry Pi 3, busca pelo sistema na rede, caso o micro SD não esteja presente. O que precisamos fazer é disponibilizar o sistema na rede, e isso requer dois caminhos distintos.
Disponibilizar o boot pelo servidor TFTP
Teremos um serviço TFTP rodando no computador servidor. A partir dele será carregado o bootloader no Raspberry que, previamente à carga do sistema raiz, deverá carregar o kernel. Para tal, criamos um diretório que conterá tudo que está em /boot de um sistema do Raspberry. Por convenção, o diretório é criado em /tftpboot. Pode ser em qualquer lugar que desejar, desde que adeque os arquivos de configuração dos serviços.
Para copiar o conteúdo da partição de boot do Raspberry existem várias formas. Particularmente, tomei o caminho mais rápido.
Tire o SD do Raspberry e, em outro Linux, faça a cópia da partição:
sudo mkdir /tftpboot sudo chown 777 /tftpboot cp -a /media/<usuario>/bootfs/* /tftpboot
Se quiser ter imagens diferentes para diferentes computadores (no caso, Raspberry), crie o diretório /tftpboot/<serial> (ou /tftpboot/mac ? Não lembro; EXPERIMENTE) e coloque o conteúdo da partição /boot lá dentro.
Disponibilizar o sistema raiz por NFS
Se não conhece, o NFS (Network File System) é um sistema de arquivos em rede. Com ele, podemos fazer compartilhamento de conteúdo como se fosse um compartilhamento SAMBA (ou compartilhamento Windows, se preferir referenciar-se a ele).
Criando um compartilhamento NFS, poderemos colocar o sistema raiz lá dentro e assim, permitir que o Raspberry carregue a raiz como se estivesse lendo de /dev/mmcblk0p2.
Para tal, crie o diretório /nfs/client1 e copie a partição raiz para lá.
sudo su mkdir -p /nfs/client1 chmod -R 777 /nfs apt-get update apt-get install rsync rsync -xa --progress /media/<usuario>/rootfs/* /nfs/client1/
Configurações iniciais de interface
Garanta que não será servidor IP por DHCP na interface interna. Crie os seguintes arquivos:
/etc/systemd/network/10-eth0.netdev
Coloque esse conteúdo:
[Match] Name=enp2s0 [Network] DHCP=no
/etc/systemd/network/11-enp2s0.netdev
Repare que aqui o arquivo tem o nome estético da interface ethernet do computador servidor. Seu conteúdo:
[Match] Name=enp2s0 [Network] Address=10.42.0.211/24 DNS=10.42.0.211 [Route] Gateway=192.168.1.1
Esse gateway nem pertence à mesma rede, mas está aí por estar. O gateway é a porta de saída de uma rede para outra, logo, o IP do gateway haveria de ser o IP da interface que está servindo o boot, exceto se o Raspberry estiver conectado a um switch, que pode lhe prover outro caminho na LAN para que ele tenha uma rota de saída da rede 10.42.0.0/24 para outra rede da LAN ou para a Internet. O caso é que não me importei de fornecer acesso à Internet, pois sendo meu notebook o servidor tftp, também haveria de configurar forwarding e mascaramento. Não é complicado, só não era o intuito, mas se desejar fazer esse roteamento, dando acesso à Internet para o Raspberry que carregou o sistema pelo TFTP, basta ler o artigo de firewall doméstico que escrevi há um bom tempo. Dadas as explicações, sigamos.
/etc/systemd/resolved.conf
Supondo que esteja configurando a rede para navegar, também será necessário especificar um servidor DNS. Tem duas formas de oferecer o recurso, mas vou deixar a cereja do bolo para o final. Por enquanto, considere preencher esse arquivo com o IP do gateway (supondo então 10.42.0.211):
[Resolve] DNS=10.42.0.211
Reiniciando serviços
Agora é hora de por os serviços para rodar, mas vamos instalar uns pacotes mais.
sudo su systemctl enable systemd-networkd reboot #depois.... sudo su apt-get install -y dnsmasq systemctl enable dnsmasq tcpdump -i enp2s0 port bootpc -vvv -XX -s9182
Aqui eu fiz o seguinte; configurei a estrela desse artigo – o dnsmasq – depois observei a interface de rede, fazendo um boot normal com o Raspberry e configurando a interface ethernet dele por DHCP para ver se o dnsmasq estava cumprindo seu papel. Vou dedicar um artigo exclusivo ao dnsmasq porque ele é demais! Mas por enquanto, vamos nos ater à configuração sem entrar nos detalhes técnicos do serviço.
Edite o arquivo /etc/dsnmasq.d/dnsmasq.conf e deixe seu conteúdo assim:
port=0 dhcp-range=10.42.0.10,10.42.0.12,12h dhcp-option=3,10.42.0.211 dhcp-option=6,10.42.0.211 log-dhcp enable-tftp tftp-root=/tftpboot pxe-service=0,"RPI Do bit Ao Byte"
Mas não vamos deixar de saber o que significa essa configuração, certo?
Protocolo DHCP e BOOTP
Existe um conjunto consideravelmente grande de regras nesses protocolos, cujas definições podem ser vistas aqui. No parâmetro dhcp-option (definido duas vezes), na primeira dizemos que o gateway é o 10.42.0.211. O código que diz se tratar do gateway é o que precede a vírgula: 3.
Posteriormente dizemos que a resolução de nome vem do mesmo endereço IP, cujo código que diz se tratar disso é o 6.
O dnsmasq, entre outras coisas, é servidor DHCP. Configuramos ele para distribuir IPs entre 10.42.0.10 e 10.42.0.12 com “lease time” de 12h. Isto é, ele não renovará o IP por 12 horas.
Hora de reiniciar o serviço para que ele assuma as configurações:
sudo su systemctl enable dnsmasq.service systemctl restart dnsmasq.service
Configurar o servidor NFS
Não podemos nos esquecer de configurar o servidor NFS, senão não tem boot do Raspberry pela rede. Esse é bastante simples:
sudo su apt-get install -y nfs-kernel-server echo "/nfs/client1 *(rw,sync,no_subtree_check,no_root_squash)" | sudo tee -a /etc/exports echo "/tftpboot *(rw,sync,no_subtree_check,no_root_squash)" | sudo tee -a /etc/exports systemctl enable rpcbind systemctl restart rpcbind systemctl enable nfs-kernel-server systemctl restart nfs-kernel-server
Como o Raspberry saberá onde buscar o sistema de arquivos?
Não adianta nada estar servindo um sistema para o boot do Raspberry pela rede se ele não souber de onde ler o sistema raiz. Essa informação não é papel do PXE, BOOTP ou DHCP. Isso já está por conta do sistema operacional, portanto, devemos configurar o sistema raiz que está no servidor para que, após o carregamento do kernel, ele possa saber onde está o restante do sistema operacional. E de onde o sistema operacional lê essa informação? – Fácil, hum? Do arquivo /boot/cmdline.txt. Nesse caso, devemos editar o arquivo /tftpboot/boot/cmdline.txt e deixá-lo assim:
console=serial0,115200 console=tty1 root=/dev/nfs nfsroot=10.42.0.211:/nfs/client1,vers=4.1,proto=tcp rw ip=dhcp rootwait elevator=deadline
Lembre-se de acertar o IP. Além disso, o boot do Raspberry pela rede será lido das definições de seus arquivos de configuração de sistema, então se estiver lendo de /tftboot/ ou /tftpboot/<serial>/boot/ ou outro nível, o sistema não iniciará. O diagnóstico é relativamente rápido; e óbvio até.
Um último ponto a considerar é a tabela de partições. Quando o sistema operacional inicia, o sistema de arquivos é montado conforme as definições que se encontram no arquivo /etc/fstab. Se estiver apontando para o UUID ou para o dispositivo de bloco diretamente, o sistema não iniciará. Desse modo, antes de fazermos qualquer teste, devemos modificar a tabela de partições no arquivo /etc/fstab. Lembre-se que, no servidor o sistema raiz ficou hospedado em /nfs/client1. Edite o arquivo /nfs/client1/etc/fstab e deixe-o assim:
proc /proc proc defaults 0 0 # a swapfile is not a swap partition, no line here # use dphys-swapfile swap[on|off] for that 10.42.0.211:/tftpboot /boot nfs defaults,vers=4.1,proto=tcp 0 0
Mais uma vez, atente-se ao IP. Um erro bobo poderá lhe causar uma bela dor de cabeça.
Só para garantir que todos os serviços serão reiniciados, talvez seja desejável reiniciar o sistema do servidor. Ao voltar, faremos uso do comando anunciado precocemente. Não se esqueça de configurar o IP 10.42.0.211 (ou a rede que disponibilizou para essa tarefa, seja uma subnet da classe A 10.0.0.0/24, 172.16.0.0/14 da classe B ou alguma rede da classe C, desde que não conflite com a rede que está utilizando para ler esse artigo). No terminal:
tcpdump -i enp2s0 -vvv -XX -s9182 port bootpc or port 69
Quando iniciar o boot do Raspberry pela rede, deverá ver informações assim:

Vou explicar algumas coisas dessa mensagem, mas não deixe de ler o artigo sobre tcpdump para ter um pouco mais de intimidade.
O início do handshake do boot do Raspberry pela rede é feito na camada de enlace de dados, onde o MAC se anuncia, esperando que um servidor DHCP lhe ofereça um IP, para então subir para a layer 3 (camada de rede). Esse anúncio pode ser visto bem no começo da segunda linha em 0.0.0.0.bootpc > 255.255.255.255.bootps, onde o boot client faz um broadcast em busca de um boot server, anunciando seu MAC. Essa não é a primeira mensagem, é a dissolução. A primeira mensagem tem esse formato:

Mas isso é só um anúncio padrão, que vai acontecer de qualquer modo. Ele pode ser útil para saber se seu Raspberry está com o suporte a bootpc, mas se seguiu o procedimento inicial para verificar o OTP, já deverá saber a resposta antes de chegar nesse ponto do artigo. Continuando da mensagem anterior, temos o anúncio (ainda da camada de enlace) que segue com [udp sum ok], sendo um bom sinal de que houve um handshake adequado. O MAC é passado mais uma vez e então outras características são informadas, mas o que importará nesse momento é ver que Your-IP e Server-IP estão preenchidos com os IPs configurados. Daí segue uma série de outros parâmetros, dos quais podemos contemplar as opções citadas anteriormente; 3 e 6, para gateway e DNS, respectivamente.
O texto é longo, mas o processo é curto. Entendendo-o, na segunda vez será rápido!
Boot do Raspberry pela rede na versão 4
Para o Raspberry Pi 4 será necessário algumas modificações, então não vou escrever a respeito agora porque o importante aqui é focar no servidor.
Onde comprar Raspberry?
E se pretende comprar Raspberry, ficam como sugestões os parceiros do blog:
Saravati – com diversas opções de Raspberry.
CurtoCircuito – para Raspberry Pi 3.
MASUGUX – Também com diversas opções de Raspberry.
Vídeo
Fiz um vídeo simples apenas para mostrar o sistema “vivo”, enquanto narro com uma bela enxaqueca, então, releve. Veja em nosso canal DobitaobyteBrasil, no Youtube. Inscreva-se e clique no sininho para receber notificações e, deixe seu like!
Espero que tenha gostado do artigo e até a próxima!
Revisão: Ricardo Amaral de Andrade