QEMU 内で dnsmasq を実行し、他の VM にネットブート サービスを提供する方法

QEMU 内で dnsmasq を実行し、他の VM にネットブート サービスを提供する方法

編集: WIP: 以下に説明する失敗の主な原因は、ホスト TAP インターフェイスを適切なタイミングで起動しなかったためです。QEMU にタップ デバイスの作成を処理させると、すべてが期待どおりに動作します。この失敗についてさらに詳しく調査し、問題がわかったらより明確な説明を提供します。ヒントを提供してくれた @anx に感謝します。

目標:dnsmasqホスト上で実行されている別の QEMU VM からのネットブートを処理するホスト QEMU VM 内でを実行します。

dnsmasq VM をゲートウェイのように動作させ、1 つの NIC をアップストリーム WAN インターフェイスとして、アップストリーム DHCP サーバーと、もう 1 つのインターフェイスをプライベート LAN インターフェイスにして、他の VM を「接続」し、このプライベート LAN インターフェイスでリッスンしている dnsmasq からネットブートするようにしたいと思います。

まず、VM同士が通信できるようにするために、ホスト上に独自のブリッジを作成します。

ip link add name vivianbr0 type bridge
ip link set vivianbr0 up

VMがホストブリッジを介して互いに通信するには、ゲートウェイVMのプライベートLANインターフェース用とプライベートVMの単一ネットワークインターフェース用の2つのタップデバイスが必要です。

ip tuntap add mode tap tap0 user cturner
ip tuntap add mode tap tap1 user cturner
ip link set tap0 up
ip link set tap1 up
ip link set tap0 master vivianbr0
ip link set tap1 master vivianbr0

ゲートウェイVMでは、テスト目的でArch Linux ISOを使用しています。VMは2つのNICで起動されるため、

 qemu-system-x86_64 \
    -drive file=arch-disk.qcow2,if=none,id=nvm \
    -device nvme,serial=deadbeef,drive=nvm \
    -cdrom archlinux-2021.09.01-x86_64.iso \
    -boot d \
    -device virtio-net-pci,romfile=,netdev=net0,mac="DE:AD:BE:EF:00:11" \
    -device virtio-net-pci,romfile=,netdev=net1,mac="DE:AD:BE:EF:00:12" \
    `# Simulate the plugged in "upstream" cable with user-mode networking` \
    -netdev user,id=net0,hostfwd=tcp::60022-:22,hostfwd=tcp::8080-:80,hostfwd=tcp::8081-:8000,hostfwd=tcp::2375-:2375 \
    `# And now the unplugged one with, with TAP networks` \
    -netdev tap,id=net1,ifname=tap0,script=no,downscript=no \
-net bridge,br=vivianbr0 \
    -m 4G \
    -enable-kvm

このマシンが起動すると、ブリッジ構成に次の内容が表示されます。

brctl show vivianbr0 

bridge name     bridge id               STP enabled     interfaces
vivianbr0               8000.46954a1ad851       no              tap0
                            tap1
                            tap2

tap2QEMU によって作成されたものだと思います...

このVM内には2つのifaceがあります。MAC ens4DE:AD:BE:EF:00:11とens5MAC DE:AD:BE:EF:00:12です。このVM内でdnsmasq

ip addr add 10.42.0.1/24 dev ens5
dnsmasq -d --dhcp-range=10.42.0.10,10.42.0.100 --dhcp-script=/bin/echo --enable-tftp=ens5 --interface=ens5

これはエラーなしで開始されます。

次に、ホスト上で次のように起動した別のVMをネットブートしてみます。

qemu-system-x86_64 \
-machine pc-q35-6.0,accel=kvm \
-m 1024 -smp 2,sockets=2,cores=1,threads=1 \
-netdev tap,id=net0,ifname=tap1,script=no,downscript=no \
-device virtio-net-pci,netdev=net0,bootindex=1,mac=DE:AD:BE:EF:00:13 \
-net bridge,br=vivianbr0 \
-enable-kvm \
-vga virtio

しかし、起動に失敗します。vivianbr0使用状況を監視しtcpdump、DHCP要求を確認できますが、応答はなく、最初のVM内で実行されているdnsmasqには何も届きません。

tcpdump -i vivianbr0 -nN
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on vivianbr0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
12:21:39.585229 IP 0.0.0.0.68 > 255.255.255.255.67: BOOTP/DHCP, Request from de:ad:be:ef:00:13, length 397
12:21:40.587741 IP 0.0.0.0.68 > 255.255.255.255.67: BOOTP/DHCP, Request from de:ad:be:ef:00:13, length 397
12:21:40.700038 IP6 fe80::6ce2:2aff:fe94:ba48.5353 > ff02::fb.5353: 0 [7q] PTR (QM)? _nfs._tcp.local. PTR (QM)? _ftp._tcp.local. PTR (QM)? _webdav._tcp.local. PTR (QM)? _webdavs._tcp.local. PTR (QM)? _sftp-ssh._tcp.local. PTR (QM)? _smb._tcp.local. PTR (QM)? _afpovertcp._tcp.local. (118)
12:21:42.619968 IP 0.0.0.0.68 > 255.255.255.255.67: BOOTP/DHCP, Request from de:ad:be:ef:00:13, length 397
12:21:46.684448 IP 0.0.0.0.68 > 255.255.255.255.67: BOOTP/DHCP, Request from de:ad:be:ef:00:13, length 397
12:22:30.609555 IP 0.0.0.0.68 > 255.255.255.255.67: BOOTP/DHCP, Request from de:ad:be:ef:00:12, length 289
12:23:33.796148 IP 0.0.0.0.68 > 255.255.255.255.67: BOOTP/DHCP, Request from de:ad:be:ef:00:12, length 289
12:24:38.673364 IP 0.0.0.0.68 > 255.255.255.255.67: BOOTP/DHCP, Request from de:ad:be:ef:00:12, length 289

de:ad:be:ef:00:13奇妙なことに、 (ネットブートVMのMACアドレス)からのBOOTPリクエストが見られます。そしてから de:ad:be:ef:00:12(ゲートウェイ VM のプライベート NIC)、何かが誤って構成されていることを示しています。

どうすればこれを機能させることができますか?

答え1

2人のゲストのための手順は問題ありません。私はあなたの設定を再現しましたアドレスをリースするまでは、dnsmasq を実行している 1 つの VM から、dhcp クライアントを実行している 1 つの VM に IP を割り当てることができました。

以下を確認してください:

  • 未接続のタップデバイスを起動できません
    • ホストの出力DOWNの状態から見える(またはと言うべき) ip a lUNKNOWNUP
      • qemuにタップデバイスを作成させると、qemu-bridge-helperそれが起動します
      • script=を使用する場合は、そこでデバイスを起動します
      • それ以外の場合は、ip link set tapN upVMの起動後にしばらく待つ必要があります
  • MACアドレスは一意である必要があります
    • ゲストのetherアドレスに表示されるip a l
    • 学習した(非ホスト)MACをリストbrctl showmacs br0します。ゼロ以外のエージングタイマーを持つエントリ
  • iptables経由でパケットをドロップする
    • モジュールがロードされている/proc/sys/net/bridge/bridge-nf-call*かどうかを確認しますbr_netfilter
    • iptables -A FORWARD -j LOG --log-prefix "forward dropped"IPv4の場合は、 FORWARDテーブルのドロップ前やDROPポリシーの前などのログルールを追加します。
    • 無視する/sys/class/net/br*/bridge/nf_call_*(なぜこれらのできるフィルタリングがオンのときはオフになります)

テスト中に見つけたその他の注目すべき点:

  • Qemu はvnet_hdr私のタップ デバイスにオプションを追加しました。これは妥当なようですし、必要に応じて qemu コマンドラインで無効にすることもできます。
  • 時々、ブリッジの (スコープ リンク) ルートが失われることがありました。それがどのようにして起こるのかはまだわかりません。

タップ デバイスにバインドすることでテストを簡素化する試みについて。

dnsmasqはQEMU VM内で実行されます

私の知る限り、永続的なタップ デバイスは実際に接続されるまで使用できません。したがって、意味のあるテストを行えるのは、次のいずれかの完全なセットアップのみです。

  • ホスト上で dnsmasq を実行しますか?
    • それをブリッジデバイスに接続します
  • または、VM 内で dnsmasq を実行しますか?
    • それぞれのネットワークインターフェースに接続します内部そのVM

--インターフェース=tap0

ヒント: --bind-interfacesdnsmasq に、他のインターフェースからのトラフィックを単に破棄するのではなく、実際にバインドを試行するように切り替えて、使用できない設定で起動したときに冗長なメッセージを表示して終了するように指示するために使用します。

関連情報