Skip to content

Instantly share code, notes, and snippets.

@comoc
Last active June 27, 2026 01:06
Show Gist options
  • Select an option

  • Save comoc/613727c045988811165fb792529485d2 to your computer and use it in GitHub Desktop.

Select an option

Save comoc/613727c045988811165fb792529485d2 to your computer and use it in GitHub Desktop.
WSL2 ミラーモード (`networkingMode=mirrored`) で DDS の接続不良多発・NATモードで解消する理由と対策

WSL2 ミラーモード (networkingMode=mirrored) で DDS の接続が不安定になる理由と対策

WSL2 のネットワークモードを mirrored(ミラーモード)にして ROS 2(CycloneDDS)を動かすと、通信の切断やノードが見つからない接続不良が起きやすく、nat(NAT モード)に戻すと解消することがあります。

この挙動の理由と、ミラーモードのまま安定させる設定をまとめます。

前提: 以下の対策は すべての ROS 2 ノードが同一の WSL2 インスタンス内で完結している 構成を想定しています。Windows 側や LAN 上の別マシンと DDS 通信する場合は、lo(ループバック)指定では通信できません。その場合は使用する実インタフェースを指定してください。


1. 接続不良が起きやすい主な理由

ミラーモードでは Windows と WSL2 がネットワークスタックを共有します。これが CycloneDDS の自動アドレス検出(ディスカバリ)と噛み合わず、接続不良につながります。主に次の 3 点が関係します。

① マルチキャストパケットのループ(エコーループ)

ROS 2(DDS)のノード探索は主に UDP マルチキャストを使います。

  • NAT モード: Windows と WSL2 は別の IP 空間に分離されており、パケットの境界が明確です。
  • ミラーモード: Windows 側のインタフェースが WSL2 側からもそのまま見えます。このため、WSL2 内の CycloneDDS が送ったマルチキャストパケットを自分自身が再受信するループが起きやすくなります。これがディスカバリの輻輳やパケットドロップを招きます。

② ネットワークインタフェース(NIC)自動選択の混乱

CycloneDDS は起動時に利用可能なインタフェースをスキャンし、通信に使う IP を自動で決めます。

  • ミラーモードでは、Windows 側の仮想アダプタ(Wi-Fi、Bluetooth、VPN、他 VM の仮想スイッチなど)が WSL2 から見えます。
  • その結果、通信が通らない不適切なインタフェースを優先バインドしてしまい、通信が成立しないことがあります。

③ Windows Defender ファイアウォールの干渉

ミラーモードでは、WSL2 内のプロセスがリスンするポートが Windows 側でも同じポートとして露出します。Windows ファイアウォールが DDS の使う UDP(7400 番台付近)のマルチキャスト通信を制限し、パケットのブロックや間引きの原因になることがあります。


2. ミラーモードのまま安定させる対策

Windows 側ツールとの兼ね合いで mirrored を維持したい場合は、CycloneDDS にどのインタフェースで通信するかを明示する設定ファイル(XML) を用意すると安定します。

ステップ 1: cyclonedds.xml の作成

WSL2 のホームディレクトリ直下などに、次の設定ファイルを作成します。

<?xml version="1.0" encoding="UTF-8" ?>
<CycloneDDS xmlns="https://cdds.io/config"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="https://cdds.io/config https://raw.githubusercontent.com/eclipse-cyclonedds/cyclonedds/master/src/core/config/src/cyclonedds.xsd">
    <Domain id="any">
        <General>
            <Interfaces>
                <NetworkInterface name="lo"/>
            </Interfaces>
            <AllowMulticast>spdp</AllowMulticast>
        </General>
    </Domain>
</CycloneDDS>

補足:

  • 上記は新しめの CycloneDDS(0.10 系以降)の <Interfaces> 形式です。古いバージョンでは <NetworkInterfaceAddress>lo</NetworkInterfaceAddress> を使います。利用バージョンに合わせてください。
  • AllowMulticastspdp にすると、ディスカバリ(SPDP)だけマルチキャストを使い、データはユニキャストになります。true(全部マルチキャスト)でも動きますが、loopback 運用では spdp が無難です。
  • lo のみで運用する場合、<Peers> でユニキャストのピアを直接指定する手もあります。

ステップ 2: loopback のマルチキャストを有効化

ここが見落としやすい点です。Linux の lo は既定で MULTICAST フラグが立っていないことが多く、その状態だと SPDP(参加者発見)が流れず、lo を指定しても繋がりません。次で確認・有効化します。

ip link show lo                  # <LOOPBACK,...> に MULTICAST が含まれるか確認
sudo ip link set lo multicast on # 含まれていなければ有効化

この設定は再起動で消えるため、恒久化するには systemd サービスなどで起動時に再実行してください。

ステップ 3: 環境変数の設定

作成した設定ファイルを CycloneDDS に読み込ませるため、~/.bashrc(または ~/.zshrc)の末尾に追記します。

export CYCLONEDDS_URI=file://$HOME/cyclonedds.xml

~/cyclonedds.xml のような bare path も新しめのバージョンなら通りますが、~ はクォートで展開されないなどの落とし穴があるため、file:// 形式が確実です。

追記後、ターミナルを再起動するか source ~/.bashrc を実行して反映させます。

効果

この設定で、CycloneDDS はミラーモードで露出した余計なインタフェースやエコーループを避け、指定したインタフェース(上記例では lo)だけで通信します。全ノードが WSL2 内で完結する構成なら、NAT モード時と同等の安定性が得られます。

Windows 側や LAN 上の別マシンと通信する場合

lo は同一 WSL2 インスタンス内の通信に限定されるため、Windows 上の ROS 2 ノードや LAN 上の別マシンとも DDS 通信したい場合は使えません。その場合は lo ではなく、外部と疎通する実インタフェース名を指定します。

インタフェース名は ip addr(または ip link)で確認できます。WSL2 では eth0 であることが多いですが、環境によって異なるので実際の名前を使ってください。

<?xml version="1.0" encoding="UTF-8" ?>
<CycloneDDS xmlns="https://cdds.io/config"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="https://cdds.io/config https://raw.githubusercontent.com/eclipse-cyclonedds/cyclonedds/master/src/core/config/src/cyclonedds.xsd">
    <Domain id="any">
        <General>
            <Interfaces>
                <NetworkInterface name="eth0"/>
            </Interfaces>
            <AllowMulticast>true</AllowMulticast>
        </General>
    </Domain>
</CycloneDDS>

補足:

  • 実インタフェースを指定してもマルチキャストが不安定なときは、AllowMulticast を無効化し、通信相手の IP を <Peers> に直接列挙してユニキャストで疎通させる方が確実です。
  • 通信相手が Windows ホストの場合、Windows Defender ファイアウォールで DDS が使う UDP(7400 番台付近)を許可する必要があります。
<!-- マルチキャストを使わずユニキャストのピアを直接指定する例 -->
<Domain id="any">
    <General>
        <Interfaces>
            <NetworkInterface name="eth0"/>
        </Interfaces>
        <AllowMulticast>false</AllowMulticast>
    </General>
    <Discovery>
        <Peers>
            <Peer Address="192.168.0.10"/>  <!-- 通信相手の IP -->
        </Peers>
    </Discovery>
</Domain>

上の例は <Domain> からの断片です。単独のファイルとして使う場合は、ステップ 1 と同じく XML 宣言と <CycloneDDS> ルート要素で囲んでください。実インタフェース指定では loopback の MULTICAST フラグ(ステップ 2)は不要です。


3. 他の RMW(Fast DDS / Zenoh)の場合

ここまでは CycloneDDS の話でした。RMW 実装によって事情が変わります。結論を先に言うと、Fast DDS は Cyclone と同じ問題が起きるので同種の対策が要りますが、Zenoh はアーキテクチャ的にこの問題をほぼ踏みません。

RMW ミラーモードでの問題 対策
CycloneDDS 起きる(マルチキャスト依存) cyclonedds.xml<Interfaces> 指定、または <Peers>
Fast DDS 起きる(同上) XML の interfaceWhiteList 指定、または Discovery Server
Zenoh ほぼ起きない(既定でマルチキャスト無効・TCP ルータ方式) 既定のまま。外部通信は connect/endpoints を明示。マルチキャスト scouting はオンにしない

Fast DDS(rmw_fastrtps_cpp / ROS 2 デフォルト)

Fast DDS も RTPS の UDP マルチキャストでディスカバリするため、エコーループや余計なインタフェースへのバインドという根は CycloneDDS と同じです。対策の考え方も同じで「使うインタフェースを明示する」ですが、設定は XML プロファイルの interfaceWhiteList で行います。

~/fastdds_profiles.xml(WSL2 内で完結するなら lo、外部通信するなら eth0 などに変更):

<?xml version="1.0" encoding="UTF-8" ?>
<profiles xmlns="http://www.eprosima.com">
    <transport_descriptors>
        <transport_descriptor>
            <transport_id>custom_udp_lo</transport_id>
            <type>UDPv4</type>
            <interfaceWhiteList>
                <interface>lo</interface>   <!-- IP で指定するなら <address>127.0.0.1</address> -->
            </interfaceWhiteList>
        </transport_descriptor>
    </transport_descriptors>
    <participant profile_name="default_participant" is_default_profile="true">
        <rtps>
            <useBuiltinTransports>false</useBuiltinTransports>
            <userTransports>
                <transport_id>custom_udp_lo</transport_id>
            </userTransports>
        </rtps>
    </participant>
</profiles>
export RMW_IMPLEMENTATION=rmw_fastrtps_cpp
export FASTDDS_DEFAULT_PROFILES_FILE=~/fastdds_profiles.xml
# 古い Fast DDS では FASTRTPS_DEFAULT_PROFILES_FILE

補足:

  • is_default_profile="true" を付けると全 ROS 2 参加者に自動適用され、プロファイル名の指定が要りません。
  • CycloneDDS と同じく、lo 限定で運用するなら loopback の MULTICAST フラグ有効化(sudo ip link set lo multicast on)が要ります。
  • useBuiltinTransportsfalse にすると共有メモリ(SHM)転送も無効になり、同一ホスト内でも UDP 経由になります。localhost 用途で SHM の速度を活かしたい場合は、SHM 用の transport_descriptor も併記して両方を有効にしてください。
  • それでもマルチキャストが不安定なら、マルチキャストを使わず Discovery Server(ROS_DISCOVERY_SERVER 環境変数)に切り替える手もあります。CycloneDDS の <Peers> ユニキャスト指定に相当する発想です。

Zenoh(rmw_zenoh)

Zenoh は仕組みが大きく違います。UDP マルチキャスト scouting が既定で無効で、各ノードは TCP で Zenoh ルータ(zenohd)に接続し、ルータ経由の gossip でディスカバリします。マルチキャストに依存しない設計だと公式にも明記されており、ミラーモードのエコーループ問題は素の状態ではまず起きません。

  • WSL2 内で完結する場合: ホストごとにルータ(ros2 run rmw_zenoh_cpp rmw_zenohd)を 1 つ立て、ノードを localhost のルータに繋ぐ標準構成のまま動きます。特別な設定は不要です。
  • Windows 側や LAN の別マシンと通信する場合: マルチキャストに頼らず、セッション設定(JSON5)の connect/endpoints に相手ルータの tcp/<IP>:7447 を列挙します(ZENOH_SESSION_CONFIG_URI / ZENOH_ROUTER_CONFIG_URI で読み込み)。
  • 注意: 同一ホスト内をルータ無しで動かそうとして ZENOH_CONFIG_OVERRIDE='scouting/multicast/enabled=true' を入れると、わざわざマルチキャストを有効化することになり、ミラーモードの問題を自分から呼び戻します。ミラーモードではオンにしないのが無難です。

この問題で素直に楽なのは Zenoh、という整理になります。


4. 参考リンク(コミュニティでの議論・既知のバグ)

この問題は ROS 2 側ではなく、WSL2 の OS / ネットワーク層に起因します。主な Issue とフォーラムスレッドを挙げます。

RMW 別の設定ドキュメント:

  • Fast DDS: Interface Whitelist interfaceWhiteList で使用インタフェースを限定する公式手順。
  • Fast DDS: XML profiles プロファイルの読み込み(FASTDDS_DEFAULT_PROFILES_FILE)と既定プロファイル指定。
  • ros2/rmw_zenoh README 既定でマルチキャスト scouting が無効・ルータ方式である旨と各環境変数の説明。
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment