Files
pf-linux-port/docs/pt-BR/vm-lab.md
T
lgcosta dff2185b20 Docs: bring the documentation in line with the code
- Demo docs replaced by the screencast docs (single source of truth): the
  legacy demo-session.sh/demo-record.py and the v0.9 renderer were removed
  instead of being kept as a second convention.
- feature-matrix: stale 'M2-in-progress' vocabulary gone; the rows the 15
  gates prove now say VERIFIED-in-VM and name the gate; af-to is now an
  explicit non-goal row (INET6 0 in this build).
- guide: the queues/divert/pflog sections described a state that no longer
  exists (priq-only, divert dropping packets, pflog logging nothing); they
  now describe the shipped behaviour.
- vm-lab: the 15 real gates with what each proves, 15/15 green, and the
  pf0 -> cli/srv/gw2 ssh setup the screencasts rely on.
- install/build: pdivert and pflogd are built and ported (docs said
  otherwise); module object list now includes hfsc.c, fq_codel.c, pfk_pflog.c;
  the screencast pipeline is an optional build stage.
- pf-guide: the 'M2 scope only' framing is gone; honest gaps listed.
- caveats: three new sections about the screencast pipeline (MiniMax video
  generation blocked by the account tier, narration as a separate track, a
  video frame is not a verdict).
- porting-notes: what the recording taught us.
- README/README.pt-BR: status, milestones, layout and video section updated.

All internal doc links verified.
2026-11-12 11:51:25 -03:00

8.1 KiB
Raw Blame History

Bancada de validação em VMs (libvirt / Alpine)

English: docs/en/vm-lab.md.

Todos os comandos abaixo foram lidos dos scripts em scripts/ (eles são a fonte de verdade); a bancada já foi criada e executada durante M0–M2 — uma rodada completa e verde da suíte é o gate do M2+ e ainda está em andamento (ver §6).

1. Onde ela mora

Host Papel
laptop (este repo) compila kernel/módulo/ferramentas; comanda tudo por ssh
deb — root@192.168.1.242 hipervisor libvirt; roda as 4 VMs Alpine pftest-*

A bancada não precisa de NAT para a internet; o único acesso externo é a rede libvirt default (192.168.122.0/24, mgmt+DHCP) usada para o cloud-init instalar pacotes e para o ssh dos testes. A sms-vm existente no deb nunca é tocada.

2. Topologia (fonte única: lab/ips.env)

VM Papel NICs Kernel
pftest-pf0 filtro sob teste (roda o pf.ko) mgmt (dhcp, rede default), lan 10.0.1.1/24, wan 10.0.2.1/24, wan2 10.0.3.1/24 Alpine padrão via boot direto do kernel extraído da imagem; ou o bzImage 7.3.4 compilado com --pf0-kernel= (root=/dev/vda2 ro console=ttyS0,115200n8, sem initrd)
pftest-cli cliente mgmt dhcp (rotas desabilitadas), lan 10.0.1.10/24, gw 10.0.1.1 (pf0) Alpine padrão
pftest-srv servidor mgmt dhcp (rotas desabilitadas), wan 10.0.2.20/24, gw 10.0.2.1 (pf0), 10.0.3.0/24 via gw2 Alpine padrão
pftest-gw2 gateway do segundo caminho (ip_forward=1) wan2 10.0.3.2/24, wan 10.0.2.2/24 (sem NIC mgmt) Alpine padrão

Todas as VMs recebem net.ipv4.ip_forward=1 e rp_filter=0 via cloud-init, senha de root pftest mais um par de chaves de laboratório injetado (/root/.ssh/pflab_ed no deb, cópia no laptop para ProxyJump), e os pacotes iperf3 tcpdump python3 scapy bash iptables (o nome no Alpine é scapy; a imagem também precisa de iptables para os experimentos de masquerade do pf0).

Redes libvirt: default (mantida como está, iniciada+autostart para os pacotes) e bridges isoladas pf-lan 10.0.1.0/24, pf-wan 10.0.2.0/24, pf-wan2 10.0.3.0/24 — forward="none", sem DHCP, mais IPs de bridge no host 10.0.x.254 no deb para que o deb consiga ssh/icmp na NIC de dados de cada guest. Dimensionamento: 2 vCPU / 1 GB por VM. Os discos são qcow2 por VM com backing na imagem compartilhada imutável /var/lib/libvirt/images/alpine-base.qcow2 (sincronizada de _vendor/images/alpine-3.22-x86_64-cloud.qcow2 por sha256).

Nota de boot: a imagem cloud do Alpine não é inicializável em BIOS/UEFI no QEMU como entregue (ESP vazia), então todas as VMs usam boot direto do kernel extraído da própria imagem; --pf0-kernel= apenas troca o kernel do pf0 pelo compilado.

3. Recriar / deployar / destruir

./scripts/vm-create.sh                       # idempotente: derruba e recria domínios + seeds pftest-*
./scripts/vm-create.sh --pf0-kernel=out/linux-7.3.4-bzImage   # pf0 sobe com o kernel compilado (T6)
./scripts/vm-create.sh --recreate-base       # força re-sync da imagem base
./scripts/vm-deploy.sh                       # laptop→deb ($DEPLOY_DIR)→pf0:/opt/pf:
                                             #   out/*bzImage, module/*.ko, tools/out/*
./scripts/vm-destroy.sh                      # domínios, discos, seeds, redes pf-* e fragmentos ssh
./scripts/vm-destroy.sh --purge-base --purge-keys   # + imagem base + chaves do lab

O vm-create.sh termina validando ssh pf0 'ip -br a' e deixa todas as VMs ligadas. Os aliases de ssh do laptop (pf0|cli|srv|gw2, ProxyJump via deb) são gerados em ~/.ssh/config.d/pflab.

Do pf0 para as outras VMs. O firewall tem seu próprio par de chaves e os pares confiam nele, então uma sessão no pf0 pode pilotar o cliente e o servidor diretamente — é isso que os screencasts fazem (ssh cli 'ping …'):

# uma vez por lab, a partir do hypervisor
ssh pf0 'ssh-keygen -t ed25519 -N "" -C pf0 -f /root/.ssh/id_ed25519'
# depois autorizar essa chave pública no cli, no srv e no gw2

O /root/.ssh/config do pf0 mapeia os nomes curtos cli, srv e gw2 para 10.0.1.10, 10.0.2.20 e 10.0.3.2, e o /etc/hosts traz o mesmo mapeamento.

4. Rodando a suíte

./scripts/vm-run-tests.sh        # ou: make test

Determinístico por projeto: antes de cada gate o runner destrói e reinicia o pftest-pf0 (delta de disco e módulo zerados), espera o ssh no endereço DHCP de mgmt 192.168.122.8, re-deploya pf.ko/pfctl/*.conf no guest e então roda o script do gate a partir do laptop (os gates falam com as VMs através do deb via ssh aninhado — tests/vm/lib.sh). A saída de cada gate é gravada em out/test-logs/<gate>.sh.log; o runner imprime PASS <gate> / FAIL <gate> (rc=...) por teste, um resumo PASS=n FAIL=m e sai com código diferente de zero se algo falhou.

5. O que cada gate prova hoje

Cada gate afirma tráfego real e estado observável, nunca apenas um código de saída: o pacote chega, é descartado ou é traduzido, e a prova é lida de volta nos contadores do próprio firewall, na tabela de estados, em capturas de pacote ou no par.

A lista completa está na §6 (15 gates, todos verdes). Cada gate é um script shell em tests/vm/ que fala com as VMs através do deb com ssh aninhado, usando os helpers de tests/vm/lib.sh (pf0, cli, srv, gw2, pfput, pfload, ok, bad). O scripts/vm-run-tests.sh roda tudo em ordem e guarda out/test-logs/<gate>.sh.log.

O que não tem gate (lacunas honestas): o caminho IPv6, o fingerprint de OS, as opções set (state-policy, allow-opts) e os syncookies — o código compila dentro do pf.ko, mas nenhum gate os exercita. O FQ-CoDel compila e compartilha o header de estatísticas com o pfctl, mas só a disciplina hfsc é exercitada.

Não existe gate numérico de performance: o bench-basic.sh não está na árvore e nenhuma meta de vazão é reivindicada.

6. Status atual da suíte (2026-11-12)

15/15 gates verdes. Uma rodada completa e limpa (./scripts/vm-run-tests.sh, ~9 min) recria e reinicia o pftest-pf0 antes de cada gate, reimplanta o módulo e as ferramentas, e termina com PASS=15 FAIL=0. Os logs capturados ficam em out/test-logs/<gate>.sh.log.

Gate O que prova hoje
01-state.sh keep state em um ping de trânsito; o estado aparece no pfctl -ss
02-block.sh block drop mata o ping; block return-rst devolve RST ao cliente
03-tables.sh uma tabela pfr bloqueia um host; um -T delete ao vivo libera o mesmo fluxo
04-anchors.sh a regra de um anchor é avaliada antes de um block posterior do ruleset principal
05-nat.sh NAT de origem: o pacote sai com o endereço do pool e a resposta é des-NATeada
06-rdr.sh redirect de porta de ponta a ponta, mais 2 MB passando com integridade byte a byte
07-binat.sh binat-to: o par vê o endereço mapeado e o original nunca vaza
08-routeto.sh route-to sai pelo link do gateway; dup-to copia e mantém o fluxo
09-scrub.sh min-ttl e max-mss medidos no egresso do próprio firewall
10-pools.sh seleção do pool de NAT (round-robin, source-hash)
11-divert.sh divert-to para o relay pdivert: o pacote vai para o userspace e volta
12-pflog.sh os pacotes logados chegam a /dev/pflog e viram um pcap DLT_PFLOG
13-replyto.sh reply-to força a resposta para o link do gateway
14-soak.sh reload de ruleset sob tráfego, ciclo de rmmod, checagem de vazamento
15-queue.sh filas hfsc: anexação, estatísticas da classe, um fluxo de 2 MB contado pela classe

Os screencasts (screencast.md) mostram boa parte desses gates sendo executados, com o diagrama de rede do lab desenhado sobre o terminal.

7. Inspeção manual

ssh pf0                       # via alias do laptop (ProxyJump deb)
insmod /opt/pf/pf.ko
/opt/pf/pfctl -e
/opt/pf/pfctl -f /tmp/g1.conf
/opt/pf/pfctl -s info ; /opt/pf/pfctl -s states -v
dmesg | grep pfk

Artefatos de rodadas completas futuras (log + pcaps) devem ir junto com o release no Gitea (spec §7).