Схема выглядит следующим образом:
Ни macvtap, ни FD‑редиректы, ни /dev/tap52 — ничего этого не нужно. Рабочая схема — только одна:
Это единственный способ, который работает в Docker‑namespace и даёт OpenWRT доступ к реальным портам.

Итоговая архитектура (рабочая)

Схема выглядит следующим образом:

enp6s0 (физика WAN)
br-wan (мост)
tap-wan (виртуальный TAP)
QEMU → eth0 (WAN в OpenWRT)
enp7s0 (физика LAN)
br-lan (мост)
tap-lan (виртуальный TAP)
QEMU → eth1 (LAN в OpenWRT)

OpenWRT внутри QEMU будет работать как настоящий роутер, потому что eth0/eth1 будут подключены к физическим портам.

Создание мостов и TAP‑интерфейсов на хосте

WAN

ip link add br-wan type bridge
ip link set br-wan up
ip link set enp6s0 master br-wan
ip tuntap add tap-wan mode tap
ip link set tap-wan up
ip link set tap-wan master br-wan

LAN

ip link add br-lan type bridge
ip link set br-lan up
ip link set enp7s0 master br-lan
ip tuntap add tap-lan mode tap
ip link set tap-lan up
ip link set tap-lan master br-lan

Проверка:

ip a | grep -E 'br-|tap-'

Правильный docker‑compose.yml

services:
  openwrt-kvm:
    build: .
    container_name: openwrt-kvm
    privileged: true
    stdin_open: true
    tty: true
    cap_add:
      - NET_ADMIN
      - NET_RAW
    devices:
      - /dev/kvm
      - /dev/net/tun
    volumes:
      - /dev:/dev
      - /opt/openwrt:/opt/openwrt
    network_mode: "none"

Почему это правильно?

  • privileged: true — QEMU получает полный доступ к KVM и TUN.
  • /dev:/dev — контейнер видит tap-wan и tap-lan, созданные на хосте.
  • network_mode: none — Docker не создаёт docker0/veth, сеть полностью под контролем QEMU.

Правильный entrypoint.sh (QEMU внутри Docker)

Создай /opt/openwrt/entrypoint.sh:

#!/bin/bash
set -e
exec qemu-system-x86_64 \
    -enable-kvm \
    -cpu host \
    -m 512 \
    -drive file=/opt/openwrt/openwrt.img,format=raw,if=virtio \
    -nographic \
    -serial mon:stdio \
    \
    -netdev tap,id=wan,ifname=tap-wan,script=no,downscript=no \
    -device virtio-net-pci,netdev=wan \
    \
    -netdev tap,id=lan,ifname=tap-lan,script=no,downscript=no \
    -device virtio-net-pci,netdev=lan

Сделать исполняемым:

chmod +x /opt/openwrt/entrypoint.sh

Конфиг OpenWRT

config interface 'wan'
    option ifname 'eth0'
    option proto 'dhcp'
config interface 'lan'
    option ifname 'eth1'
    option proto 'static'
    option ipaddr '192.168.10.1'
    option netmask '255.255.255.0'

OpenWRT в Docker работает через физические порты хоста

  • eth0 в OpenWRT = enp6s0 на хосте
  • eth1 в OpenWRT = enp7s0 на хосте
  • DHCP, NAT, firewall — всё работает как на железном роутере
  • скорость = скорость физического интерфейса
  • никаких macvtap, никаких FD, никаких namespace‑конфликтов