# eBPF Sockmap — Acelerador de comunicação entre containers Docker ## 📖 O que é isso? Este projeto usa **eBPF sockmap** para **acelerar a comunicação de rede entre containers Docker** que rodam no mesmo servidor (host). ### A stack de exemplo inclui: | Container | Função | Porta | |-----------|--------|-------| | **Nginx** | Proxy reverso | 8080 → 80 | | **Node.js** | Servidor da aplicação | 3000 | | **MySQL** | Banco de dados relacional | 3306 | | **PostgreSQL** | Banco de dados relacional | 5432 | --- ## 🧠 Como funciona? (Explicação para iniciantes) ### O problema: comunicação lenta entre containers Quando dois containers Docker no mesmo host se comunicam (ex: Node.js → MySQL), os dados passam por **toda a pilha de rede do Linux**: ``` Container A (Node.js) ↓ syscall send() ↓ TCP (segmentação, controle de fluxo) ↓ IP (roteamento) ↓ Netfilter (iptables/nftables) ↓ Bridge (docker0) ↓ veth pair (interface virtual) ↓ IP (de novo) ↓ TCP (de novo) ↓ syscall recv() Container B (MySQL) ``` Isso é **desnecessário** quando os containers estão no **mesmo host** — os dados poderiam ir direto de um para o outro! ### A solução: eBPF Sockmap Com o sockmap, os dados são **redirecionados diretamente entre sockets**, pulando TODA essa pilha: ``` Container A (Node.js) ↓ syscall send() ↓ eBPF intercepta aqui! ⚡ ↓ Dados vão direto para o socket do outro container ↓ syscall recv() Container B (MySQL) ``` ### Os dois programas BPF O projeto tem **dois programas eBPF** que trabalham juntos: #### 1. `sock_ops` — O Registrador - É ativado toda vez que uma **conexão TCP é estabelecida** - Quando o Node.js conecta no MySQL, ele **registra esses sockets** num mapa (tabela hash) - O mapa guarda: IP origem, IP destino, porta origem, porta destino → socket #### 2. `sk_msg` — O Redirecionador - É ativado toda vez que um **socket registrado envia dados** - Ele procura no mapa o socket do **outro lado** da conexão - Se encontrar, **redireciona os dados diretamente** para lá - Se não encontrar, deixa passar normalmente pela rede ``` ┌─────────────────────────────────────────────────────────────┐ │ KERNEL LINUX │ │ │ │ ┌──────────┐ sock_ops ┌──────────────┐ │ │ │ Conexão │ ──registra socket──→ │ SOCKHASH │ │ │ │ TCP nova │ │ (mapa BPF) │ │ │ └──────────┘ │ │ │ │ │ key → sock │ │ │ ┌──────────┐ sk_msg │ key → sock │ │ │ │ Socket │ ──procura par──────→ │ key → sock │ │ │ │ envia │ └──────────────┘ │ │ │ dados │ ←─redireciona direto──────────┘ │ │ └──────────┘ │ │ │ │ ✂️ Pula: TCP/IP → Netfilter → Bridge → veth → TCP/IP │ └─────────────────────────────────────────────────────────────┘ ``` --- ## 📋 Requisitos | Requisito | Mínimo | Verificar | |-----------|--------|-----------| | **Linux** | Kernel ≥ 5.4 | `uname -r` | | **BTF** | Habilitado no kernel | `ls /sys/kernel/btf/vmlinux` | | **Cgroup v2** | Ativo | `mount \| grep cgroup2` | | **Clang/LLVM** | ≥ 11 | `clang --version` | | **bpftool** | Instalado | `bpftool version` | | **libbpf-dev** | Headers instalados | `dpkg -l libbpf-dev` | | **Docker** | ≥ 20.10 | `docker --version` | | **Docker Compose** | v2 (plugin) | `docker compose version` | > **⚠️ IMPORTANTE:** eBPF roda **apenas no Linux**. Se você está no Windows, use **WSL2** ou uma **VM Linux**. --- ## 🚀 Guia passo a passo ### Passo 0: Entrar no Linux (se usa Windows) Se você está no Windows, precisa usar WSL2: ```bash # No PowerShell do Windows, abra o WSL: wsl # Navegue até o projeto: cd /mnt/c/Users/rodri/build/ebpf-sockmap ``` ### Passo 1: Instalar dependências ```bash # Instala TUDO que é necessário automaticamente sudo bash scripts/setup.sh ``` Ou instale manualmente (Ubuntu/Debian): ```bash sudo apt update sudo apt install -y \ clang llvm libbpf-dev \ linux-tools-common linux-tools-$(uname -r) \ linux-headers-$(uname -r) \ build-essential pkg-config curl \ docker.io docker-compose-plugin ``` ### Passo 2: Compilar o programa eBPF ```bash # Compila tudo (gera vmlinux.h + compila o .c para .o) make ``` **O que acontece:** 1. `bpftool` gera o arquivo `vmlinux.h` a partir do kernel atual (contém todas as definições de estruturas do kernel) 2. `clang` compila o `sockmap.bpf.c` para bytecode BPF → `build/sockmap.bpf.o` Se der tudo certo, você verá: ``` ✅ Compilação concluída! Objeto BPF em: build/sockmap.bpf.o ``` ### Passo 3: Subir os containers Docker ```bash # Sobe nginx + node.js + mysql + postgresql make docker-up ``` Aguarde até todos estarem prontos (pode levar ~30s na primeira vez): ```bash # Verifique se está funcionando: curl http://localhost:8080/ curl http://localhost:8080/mysql/users curl http://localhost:8080/postgres/products ``` ### Passo 4: Benchmark SEM sockmap (linha de base) ```bash # Anota os tempos sem o sockmap ativo bash scripts/benchmark.sh ``` Guarde os resultados para comparar depois! ### Passo 5: Ativar o eBPF Sockmap ```bash # Carrega e ativa o sockmap make load ``` Saída esperada: ``` [OK] Programa sock_ops carregado [OK] Programa sk_msg carregado [OK] sock_ops anexado ao cgroup [OK] sk_msg anexado ao sockhash [OK] eBPF Sockmap ATIVADO com sucesso! ``` ### Passo 6: Benchmark COM sockmap (comparar!) ```bash # Roda o mesmo benchmark, agora com sockmap ativo bash scripts/benchmark.sh ``` Você deve ver **melhoria na latência**, especialmente nas queries ao banco de dados. ### Passo 7: Ver status e estatísticas ```bash make status ``` ### Passo 8: Desativar quando quiser ```bash # Remove o sockmap (volta ao comportamento normal) make unload # Para os containers make docker-down ``` --- ## 📁 Estrutura do projeto ``` ebpf-sockmap/ ├── bpf/ │ ├── sockmap.bpf.c ← Programa eBPF (sock_ops + sk_msg) │ └── vmlinux.h ← (gerado) Definições do kernel ├── build/ │ └── sockmap.bpf.o ← (gerado) Bytecode BPF compilado ├── docker/ │ ├── docker-compose.yml ← Definição dos 4 containers │ ├── nginx/ │ │ └── nginx.conf ← Config do proxy reverso │ ├── app/ │ │ ├── Dockerfile ← Build do container Node.js │ │ ├── server.js ← Servidor com endpoints de teste │ │ └── package.json ← Dependências Node.js │ └── db/ │ ├── mysql-init.sql ← Schema inicial MySQL │ └── postgres-init.sql← Schema inicial PostgreSQL ├── scripts/ │ ├── loader.sh ← Carrega/descarrega o eBPF sockmap │ ├── setup.sh ← Instala todas as dependências │ └── benchmark.sh ← Testa latência ├── Makefile ← Comandos de build e operação └── README.md ← Este arquivo ``` --- ## 🔍 Comandos úteis ```bash make help # Lista todos os comandos disponíveis make # Compila tudo make docker-up # Sobe os containers make docker-down # Para os containers make docker-logs # Vê logs em tempo real make load # Ativa o sockmap make unload # Desativa o sockmap make status # Mostra estatísticas make benchmark # Testa performance make clean # Limpa compilados ``` --- ## 🐛 Solução de problemas ### "bpftool não encontrado" ```bash # Ubuntu/Debian sudo apt install linux-tools-common linux-tools-$(uname -r) # Se ainda não funcionar, procure o caminho: find /usr/lib -name bpftool 2>/dev/null ``` ### "BTF não encontrado" (/sys/kernel/btf/vmlinux não existe) Seu kernel não foi compilado com BTF. Opções: - Atualizar para um kernel mais recente da distro - Compilar o kernel com `CONFIG_DEBUG_INFO_BTF=y` ### "Cgroup v2 não detectado" ```bash # Adicione ao GRUB: sudo nano /etc/default/grub # Na linha GRUB_CMDLINE_LINUX, adicione: # systemd.unified_cgroup_hierarchy=1 sudo update-grub sudo reboot ``` ### "Permissão negada" O eBPF precisa de privilégios de root: ```bash sudo make load ``` ### Containers não sobem ```bash # Veja os logs: make docker-logs # Verifique se as portas estão livres: sudo lsof -i :8080 sudo lsof -i :3306 sudo lsof -i :5432 ``` ### WSL2: eBPF não funciona O kernel padrão do WSL2 pode não ter suporte completo. Opções: 1. Compilar um kernel customizado para WSL2 com BTF 2. Usar uma VM Linux (VirtualBox ou VMware) com Ubuntu 22.04+ --- ## 📚 Conceitos para entender melhor ### O que é eBPF? **eBPF** (extended Berkeley Packet Filter) é uma tecnologia do Linux que permite executar pequenos programas **dentro do kernel**, de forma segura. É usado para: - Monitoramento de rede (tcpdump, Cilium) - Segurança (Falco, Tetragon) - Performance (bcc tools, bpftrace) - **Aceleração de rede** (sockmap — nosso caso!) ### O que é um Sockmap/Sockhash? Um **sockhash** é um tipo de mapa BPF que armazena **referências a sockets**. É como uma tabela onde: - **Chave** = informações da conexão (IPs + portas) - **Valor** = referência ao socket do kernel ### Por que isso é mais rápido? Sem sockmap, dados entre containers passam por ~12 camadas de processamento no kernel. Com sockmap, passam por apenas 2 (o programa BPF e a cópia de memória). ### Limitações - Funciona apenas para containers **no mesmo host** - Apenas **TCP** (não UDP) - Apenas **IPv4** (esta implementação) - Precisa de kernel moderno (≥ 5.4) - Precisa de cgroup v2 --- ## 📊 Resultados esperados A melhoria depende do cenário, mas tipicamente: | Métrica | Sem Sockmap | Com Sockmap | Melhoria | |---------|-------------|-------------|----------| | Latência query MySQL | ~0.5ms | ~0.2ms | ~60% | | Latência query PostgreSQL | ~0.5ms | ~0.2ms | ~60% | | Latência HTTP (nginx→node) | ~1.0ms | ~0.4ms | ~60% | | Throughput (req/s) | ~5000 | ~8000 | ~60% | > Os valores são aproximados e variam conforme o hardware e carga. --- ## 📜 Licença GPL-2.0 (exigido pelo eBPF/kernel Linux)