Google は、黒人コミュニティのための人種的公平の促進に取り組んでいます。詳細をご覧ください。

Docker で OpenThread を使用してスレッド ネットワークをシミュレートする

1. はじめに

26b7f4f6b3ea0700.png

Google がリリースした OpenThread は、Thread ネットワーキング プロトコルのオープンソース実装です。Google Nest は、Google Nest 製品で使用されるテクノロジーを広く利用できるようにするために OpenThread をリリースし、スマートホーム製品の開発を加速させてきました。

Thread 仕様は、家庭用アプリケーション向けの IPv6 ベースの信頼性が高く、安全で低電力のワイヤレス デバイス間通信プロトコルを定義しています。OpenThread は、MAC セキュリティ、メッシュリンク確立、メッシュルーティングを備えた IPv6、6LoWPAN、IEEE 802.15.4 を含むすべてのスレッドネットワーキングレイヤを実装します。

この Codelab では、Docker を使用してエミュレートしたデバイスで Thread ネットワークをシミュレートする方法について説明します。

学習内容

  • OpenThread ビルド ツールチェーンを設定する方法
  • Thread ネットワークをシミュレートする方法
  • Thread ノードを認証する方法
  • OpenThread Daemon を使用して Thread ネットワークを管理する方法

必要なもの

  • Docker
  • Linux、ネットワーク ルーティングに関する基本的な知識

2. Docker の設定

この Codelab は、Linux、Mac OS X、Windows マシン上の Docker を使用するように設計されています。推奨される環境は Linux です。

Docker のインストール

任意の OS に Docker をインストールします。

Docker イメージを pull する

Docker をインストールしたら、ターミナル ウィンドウを開き、openthread/environment Docker イメージを pull します。このイメージには、OpenThread と OpenThread Daemon がビルド済みで、この Codelab で使用できる状態になっています。

$ docker pull openthread/environment:latest

ダウンロードが完了するまでに数分かかることがあります。

ターミナル ウィンドウで、イメージから Docker コンテナを起動し、その bash シェルに接続します。

$ docker run --name codelab_otsim_ctnr -it --rm \
   --sysctl net.ipv6.conf.all.disable_ipv6=0 \
   --cap-add=net_admin openthread/environment bash

この Codelab では次のフラグが必要です。

  • --sysctl net.ipv6.conf.all.disable_ipv6=0 - コンテナ内で IPv6 が有効になります
  • --cap-add=net_admin - NET_ADMIN 機能が有効になり、IP ルートの追加などのネットワーク関連操作を実行できるようになります。

コンテナに入ると、次のようなプロンプトが表示されます。

root@c0f3912a74ff:/#

上記の例では、c0f3912a74ff がコンテナ ID です。Docker コンテナのインスタンスのコンテナ ID は、この Codelab のプロンプトに表示される ID とは異なります。

Docker の使用

この Codelab は、Docker の基本的な使用方法を理解していることを前提としています。Codelab 全体は、Docker コンテナ内で行う必要があります。

3. Thread ネットワークをシミュレートする

この Codelab で使用するサンプル アプリケーションは、基本的なコマンドライン インターフェース(CLI)を介して OpenThread 構成および管理インターフェースを公開する、最小限の OpenThread アプリケーションです。

この演習では、エミュレートされた Thread デバイスから別のエミュレートされた Thread デバイスに ping を行うために必要な最小限の手順を説明します。

次の図に、基本的な Thread ネットワーク トポロジを示します。この演習では、緑色の円の中の 2 つのノード(Thread Leader と Thread Router 間の単一接続)をエミュレートします。

6e3aa07675f902dc.png

ネットワークを作成する

1. ノード 1 を起動します

まだ行っていない場合は、ターミナル ウィンドウで Docker コンテナを起動しbash シェルに接続します。

$ docker run --name codelab_otsim_ctnr -it --rm \
   --sysctl net.ipv6.conf.all.disable_ipv6=0 \
   --cap-add=net_admin openthread/environment bash

Docker コンテナで、ot-cli-ftd バイナリを使用して、エミュレートされた Thread デバイスの CLI プロセスを生成します。

root@c0f3912a74ff:/# /openthread/build/examples/apps/cli/ot-cli-ftd 1

注: このコマンドを実行した後に > プロンプトが表示されない場合は、enter を押してください。

このバイナリは OpenThread デバイスを実装します。IEEE 802.15.4 無線ドライバは UDP 上に実装されています(IEEE 802.15.4 フレームは UDP ペイロードで渡されます)。

1 の引数は、「ファクトリ割り当て」の最下位ビットを表すファイル記述子です。エミュレートされたデバイスの IEEE EUI-64 です。この値は、IEEE 802.15.4 無線エミュレーション(ポート = 9000 + ファイル記述子)の UDP ポートにバインドする場合にも使用されます。この Codelab のエミュレートされた Thread デバイスの各インスタンスは、異なるファイル記述子を使用します。

注: エミュレートしたデバイスのプロセスを生成する際は、この Codelab の記述に沿って 1 以上のファイル記述子のみを使用してください。0 のファイル記述子は他の使用のために予約されています。

新しい運用データセットを作成し、アクティブなデータセットとして commit します。オペレーション データセットは、作成する Thread ネットワークの構成です。

> dataset init new
Done
> dataset
Active Timestamp: 1
Channel: 20
Channel Mask: 07fff800
Ext PAN ID: d6263b6d857647da
Mesh Local Prefix: fd61:2344:9a52:ede0/64
Network Key: e4344ca17d1dca2a33f064992f31f786
Network Name: OpenThread-c169
PAN ID: 0xc169
PSKc: ebb4f2f8a68026fc55bcf3d7be3e6fe4
Security Policy: 0, onrcb
Done

このデータセットをアクティブなデータセットとして commit します。

> dataset commit active
Done

IPv6 インターフェースを起動します。

> ifconfig up
Done

Thread プロトコル オペレーションを開始します。

> thread start
Done

数秒待ってから、デバイスが Thread Leader になったことを確認します。リーダーは、ルーター ID の割り当てを管理するデバイスです。

> state
leader
Done

ノード 1 のスレッド インターフェースに割り当てられた IPv6 アドレスを表示します(出力は異なります)。

> ipaddr
fd61:2344:9a52:ede0:0:ff:fe00:fc00
fd61:2344:9a52:ede0:0:ff:fe00:5000
fd61:2344:9a52:ede0:d041:c5ba:a7bc:5ce6
fe80:0:0:0:94da:92ea:1353:4f3b
Done

特定の IPv6 アドレスタイプに注意してください。

  • fd = Mesh-local で始まる
  • 先頭が fe80 = リンクローカル

メッシュのローカル アドレスタイプはさらに分類されます。

  • ff:fe00 = Router ロケーター(RLOC)を含む
  • ff:fe00 を含まない = エンドポイント識別子(EID)

コンソール出力で後で使用できるように、EID をメモしておきます。上記のサンプル出力では、EID は次のようになります。

fd61:2344:9a52:ede0:d041:c5ba:a7bc:5ce6

2. ノード 2 を起動します

新しいターミナルを開き、現在実行中の Docker コンテナで bash シェルを実行してノード 2 に使用します。

$ docker exec -it codelab_otsim_ctnr bash

この新しい bash プロンプトで、引数 2 を指定して CLI プロセスを生成します。2 つ目のエミュレートされた Thread デバイスです。

root@c0f3912a74ff:/# /openthread/build/examples/apps/cli/ot-cli-ftd 2

注: このコマンドを実行した後に > プロンプトが表示されない場合は、enter を押してください。

ノード 1 の運用データセットと同じ値を使用して、スレッド ネットワーク キーと PAN ID を設定します。

> dataset networkkey e4344ca17d1dca2a33f064992f31f786
Done
> dataset panid 0xc169
Done

このデータセットをアクティブなデータセットとして commit します。

> dataset commit active
Done

IPv6 インターフェースを起動します。

> ifconfig up
Done

Thread プロトコル オペレーションを開始します。

> thread start
Done

デバイス自体が子として初期化されます。スレッドの子はエンドデバイスに相当します。エンドデバイスは、親デバイスとのみユニキャスト トラフィックを送受信するスレッド デバイスです。

> state
child
Done

2 分以内に、状態が child から router に変わります。Thread Router は、Thread デバイス間でトラフィックをルーティングできます。親とも呼ばれます。

> state
router
Done

ネットワークを確認する

メッシュ ネットワークを確認する簡単な方法は、ルーターのテーブルを確認することです。

1. 接続を確認する

ノード 2 で RLOC16 を取得します。RLOC16 は、デバイスの RLOC IPv6 アドレスの最後の 16 ビットです。

> rloc16
5800
Done

ノード 1 のルーターの表でノード 2 の RLOC16 を確認します。まず、ノード 2 がルーターの状態に切り替わっていることを確認します。

> router table
| ID | RLOC16 | Next Hop | Path Cost | LQ In  | LQ Out  | Age | Extended MAC   |
+----+--------+----------+-----------+--------+-------+---+--------------------+
| 20 | 0x5000 |       63 |         0 |      0 |     0 |   0 | 96da92ea13534f3b |
| 22 | 0x5800 |       63 |         0 |      3 |     3 |  23 | 5a4eb647eb6bc66c |

ノード 2 の 0x5800 の RLOC がテーブルにあり、それがメッシュに接続されていることを確認します。

2. ノード 2 からノード 1 に ping を実行する

2 つのエミュレートされた Thread デバイス間の接続を確認します。ノード 2 で、ノード 1 に割り当てられた EID を ping します。

> ping fd61:2344:9a52:ede0:d041:c5ba:a7bc:5ce6
> 16 bytes from fd61:2344:9a52:ede0:d041:c5ba:a7bc:5ce6: icmp_seq=1 hlim=64 time=12ms

enter キーを押して > CLI のプロンプトに戻ります。

ネットワークをテストする

2 つのエミュレートされた Thread デバイス間で正常に ping を実行できるようになったので、1 つのノードをオフラインにしてメッシュ ネットワークをテストします。

ノード 1 に戻ってスレッドを停止します。

> thread stop
Done

ノード 2 に切り替えて状態を確認する。2 分以内に、ノード 2 はリーダー(ノード 1)がオフラインであることを検出すると、ノード 2 がネットワークの leader に遷移することを確認します。

> state
router
Done
...
> state
leader
Done

確認したら、スレッドを停止し、ノード 2 を出荷時設定にリセットしてから、Docker bash プロンプトに戻ります。出荷時の設定へのリセットは、この演習で使用した Thread ネットワーク認証情報が次の演習に引き継がれるように行われます。

> thread stop
Done
> factoryreset
>
> exit
root@c0f3912a74ff:/#

factoryreset コマンドの後に > プロンプトに戻るには、enter を数回押すことが必要になる場合があります。Docker コンテナは終了しないでください。

また、ノード 1 を出荷時の設定にリセットして終了します。

> factoryreset
>
> exit
root@c0f3912a74ff:/#

使用可能なすべての CLI コマンドについては、OpenThread CLI リファレンスをご覧ください。

4. コミッショニングでノードを認証する

前の演習では、2 つのシミュレーション デバイスと確認済みの接続を使用して Thread ネットワークを設定します。ただし、この方法では、認証されていない IPv6 リンクローカル トラフィックのみをデバイス間で通過させることができます。ノード間で(および Thread の境界ルーターを介したインターネットで)グローバル IPv6 トラフィックをルーティングするには、ノードを認証する必要があります。

認証を行うには、1 台のデバイスがコミッショナーとして動作する必要があります。コミッショナーは、新しい Thread デバイス用に現在選択されている認証サーバーであり、デバイスがネットワークに参加するために必要なネットワーク認証情報を提供するための承認者です。

この演習では、前と同じ 2 ノードトポロジを使用します。Thread リーダーはコミッショナーとして、Thread ルーターは Joiner として機能します。

d6a67e8a0d0b5dcb.png

Docker

残りの演習では、各ノード(ターミナル ウィンドウ)で OpenThread ビルドの Docker コンテナが実行中であることを確認します。前の演習から続行する場合、同じ Docker コンテナ内に 2 つの bash プロンプトをすでに開いているはずです。そうでない場合は、Docker のトラブルシューティング手順をご覧ください。または、Thread ネットワークをシミュレートする演習をやり直してください。

1. ネットワークの作成

ノード 1 で、CLI プロセスを生成します。

root@c0f3912a74ff:/# /openthread/build/examples/apps/cli/ot-cli-ftd 1

注: このコマンドを実行した後に > プロンプトが表示されない場合は、enter を押してください。

新しい運用データセットを作成し、アクティブなデータセットとして commit して Thread を起動します。

> dataset init new
Done
> dataset
Active Timestamp: 1
Channel: 12
Channel Mask: 07fff800
Ext PAN ID: e68d05794bf13052
Mesh Local Prefix: fd7d:ddf7:877b:8756/64
Network Key: a77fe1d03b0e8028a4e13213de38080e
Network Name: OpenThread-8f37
PAN ID: 0x8f37
PSKc: f9debbc1532487984b17f92cd55b21fc
Security Policy: 0, onrcb
Done

このデータセットをアクティブなデータセットとして commit します。

> dataset commit active
Done

IPv6 インターフェースを起動します。

> ifconfig up
Done

Thread プロトコル オペレーションを開始します。

> thread start
Done

数秒待ってから、デバイスが Thread リーダーになったことを確認します。

> state
leader
Done

2. コミッショナーのロールを開始する

ノード 1 で、コミッショナーのロールを開始します。

> commissioner start
Done

* ワイルドカードを使用して)任意の Joiner に、J01NME Joiner 認証情報を使用してネットワークへのコミッションを許可します。Joiner は、委託先のスレッド ネットワークに人間の管理者が追加するデバイスです。

> commissioner joiner add * J01NME
Done

3. Joiner のロールを開始する

2 つ目のターミナル ウィンドウで、Docker コンテナで新しい CLI プロセスを生成します。これはノード 2 です。

root@c0f3912a74ff:/# /openthread/build/examples/apps/cli/ot-cli-ftd 2

ノード 2 で、J01NME Joiner 認証情報を使用して Joiner ロールを有効にします。

> ifconfig up
Done
> joiner start J01NME
Done

... 確認まで数秒待ちます ...

Join success

Joiner として、デバイス(ノード 2)はコミッショナー(ノード 1)で自身を正常に認証し、Thread ネットワーク認証情報を受信します。

ノード 2 が認証されたら、Thread を起動します。

> thread start
Done

4. ネットワーク認証を検証する

ノード 2 の state を調べて、ネットワークに参加していることを確認します。2 分以内に、ノード 2 は child から router に移行します。

> state
child
Done
...
> state
router
Done

5. 構成をリセット

次の演習に備えて、構成をリセットします。各ノードで Thread を停止し、出荷時の設定にリセットし、エミュレートされた Thread デバイスを終了します。

> thread stop
Done
> factoryreset
>
> exit
root@c0f3912a74ff:/#

factoryreset コマンドの後に > プロンプトに戻るには、enter を数回押すことが必要になる場合があります。

5. OpenThread Daemon を使用してネットワークを管理する

この演習では、1 つの CLI インスタンス(1 つの組み込み SoC スレッド デバイス)と 1 つの無線コプロセッサ(RCP)インスタンスをシミュレートします。

ot-daemon は、UNIX ソケットを入力と出力として使用する OpenThread Posix アプリのモードです。これにより、OpenThread コアをサービスとして実行できます。クライアントは、OpenThread CLI をプロトコルとして使用してソケットに接続することで、このサービスと通信できます。

ot-ctl は、RCP を管理および構成するために ot-daemon によって提供される CLI です。これを使用して、RCP をスレッド デバイスによって作成されたネットワークに接続します。

Docker

この演習の各ノード(ターミナル ウィンドウ)では、必ず OpenThread ビルドで Docker コンテナが実行されていることを確認してください。前の演習を続けると、同じ Docker コンテナ内にすでに 2 つの bash プロンプトが開いているはずです。そうでない場合は、Docker のトラブルシューティングの手順をご覧ください。

ot-daemon を使用する

この演習では、以下に対応する 3 つのターミナル ウィンドウを使用します。

  1. シミュレートされた Thread デバイスの CLI インスタンス(ノード 1)
  2. ot-daemon 個のプロセス
  3. ot-ctl CLI インスタンス

1. ノード 1 を起動します

最初のターミナル ウィンドウで、エミュレートした Thread デバイスの CLI プロセスを生成します。

root@c0f3912a74ff:/# /openthread/build/examples/apps/cli/ot-cli-ftd 1

注: このコマンドを実行した後に > プロンプトが表示されない場合は、enter を押してください。

新しい運用データセットを作成し、アクティブなデータセットとして commit して Thread を起動します。

> dataset init new
Done
> dataset
Active Timestamp: 1
Channel: 13
Channel Mask: 07fff800
Ext PAN ID: 97d584bcd493b824
Mesh Local Prefix: fd55:cf34:dea5:7994/64
Network Key: ba6e886c7af50598df1115fa07658a83
Network Name: OpenThread-34e4
PAN ID: 0x34e4
PSKc: 38d6fd32c866927a4dfcc06d79ae1192
Security Policy: 0, onrcb
Done

このデータセットをアクティブなデータセットとして commit します。

> dataset commit active
Done

IPv6 インターフェースを起動します。

> ifconfig up
Done

Thread プロトコル オペレーションを開始します。

> thread start
Done

ノード 1 のスレッド インターフェースに割り当てられた IPv6 アドレスを表示します。

> ipaddr
fd55:cf34:dea5:7994:0:ff:fe00:fc00
fd55:cf34:dea5:7994:0:ff:fe00:d000
fd55:cf34:dea5:7994:460:872c:e807:c4ab
fe80:0:0:0:9cd8:aab6:482f:4cdc
Done
>

スレッド ネットワークをシミュレートする手順で説明したように、1 つのアドレスはリンクローカル(fe80)で、3 つのアドレスはメッシュローカル(fd)です。EID は、アドレスに ff:fe00 を含まないメッシュ ローカル アドレスです。このサンプル出力では、EID は fd55:cf34:dea5:7994:460:872c:e807:c4ab です。

ipaddr 出力から特定の EID を特定します。これは、ノードとの通信に使用されます。

2. ot-daemon を起動する

2 つ目のターミナル ウィンドウで、tun デバイスノードを作成し、読み取り/書き込み権限を設定します。

root@c0f3912a74ff:/# mkdir -p /dev/net && mknod /dev/net/tun c 10 200
root@c0f3912a74ff:/# chmod 600 /dev/net/tun

このデバイスは、仮想デバイスのパケットの送受信に使用されます。デバイスがすでに作成されている場合、エラーが表示されることがあります。これは正常な動作であり、無視してかまいません。

RCP ノード用に ot-daemon を起動します。これはノード 2 と呼びます。-v 詳細フラグを使用すると、ログ出力を表示して実行されています。

root@c0f3912a74ff:/# /openthread/build/posix/src/posix/ot-daemon -v \
'spinel+hdlc+forkpty://openthread/build/examples/apps/ncp/ot-rcp?forkpty-arg=2'

成功すると、詳細モードの ot-daemon は次のような出力を生成します。

ot-daemon[31]: Running OPENTHREAD/297a880; POSIX; Feb  1 2022 04:43:39
ot-daemon[31]: Thread version: 3
ot-daemon[31]: Thread interface: wpan0
ot-daemon[31]: RCP version: OPENTHREAD/297a880; SIMULATION; Feb  1 2022 04:42:50

このターミナルは開いたまま、バックグラウンドで動作したままにします。これ以降はコマンドを入力しません。

3. ot-ctl を使用してネットワークに参加する

ノード 2(ot-daemon RCP)をまだ Thread ネットワークに送信していません。そこで役立つのが ot-ctl です。ot-ctl は OpenThread CLI アプリと同じ CLI を使用するため、他のシミュレーション Thread デバイスと同じ方法で ot-daemon ノードを制御できます。

3 つ目のターミナル ウィンドウを開き、既存のコンテナを実行します。

$ docker exec -it codelab_otsim_ctnr bash

コンテナ内で、ot-ctl を開始します。

root@c0f3912a74ff:/# /openthread/build/posix/src/posix/ot-ctl
>

この 3 つ目のターミナル ウィンドウで ot-ctl を使用し、ot-daemon を使って 2 つ目のターミナル ウィンドウで開始したノード 2(RCP ノード)を管理します。ノード 2 の state を確認します。

> state
disabled
Done

ノード 2 の eui64 を取得し、参加を特定の Joiner に制限します。

> eui64
18b4300000000001
Done

ノード 1(最初のターミナル ウィンドウ)で、Commissioner を起動し、参加を eui64 のみに制限します。

> commissioner start
Done
> commissioner joiner add 18b4300000000001 J01NME
Done

3 つ目のターミナル ウィンドウで、ノード 2 のネットワーク インターフェースを起動してネットワークに参加します。

> ifconfig up
Done
> joiner start J01NME
Done

... 確認まで数秒待ちます ...

Join success

Joiner として、RCP(ノード 2)はコミッショナー(ノード 1)で自身を正常に認証し、Thread ネットワーク認証情報を受信します。

次に、ノード 2 を Thread ネットワークに接続します(ここでも、第 3 のターミナル ウィンドウに入ります)。

> thread start
Done

4. ネットワーク認証を検証する

3 番目のターミナルで、ノード 2 の state を調べて、ネットワークに参加していることを確認します。2 分以内に、ノード 2 は child から router に移行します。

> state
child
Done
...
> state
router
Done

5. 接続の検証

3 つ目のターミナル ウィンドウで、Ctrl+D または exit コマンドを使用して ot-ctl を終了し、コンテナの bash コンソールに戻ります。このコンソールから、ping6 コマンドを使用して EID を使用して、ノード 1 に ping を実行します。ot-daemon RCP インスタンスが Thread ネットワークに正常に参加して Thread ネットワークと通信した場合、ping は成功します。

root@c0f3912a74ff:/# ping6 -c 4 fd55:cf34:dea5:7994:460:872c:e807:c4ab
PING fd55:cf34:dea5:7994:460:872c:e807:c4ab (fd55:cf34:dea5:7994:460:872c:e807:c4ab): 56 data bytes
64 bytes from fd55:cf34:dea5:7994:460:872c:e807:c4ab: icmp_seq=0 ttl=64 time=4.568 ms
64 bytes from fd55:cf34:dea5:7994:460:872c:e807:c4ab: icmp_seq=1 ttl=64 time=6.396 ms
64 bytes from fd55:cf34:dea5:7994:460:872c:e807:c4ab: icmp_seq=2 ttl=64 time=7.594 ms
64 bytes from fd55:cf34:dea5:7994:460:872c:e807:c4ab: icmp_seq=3 ttl=64 time=5.461 ms
--- fd55:cf34:dea5:7994:460:872c:e807:c4ab ping statistics ---
4 packets transmitted, 4 packets received, 0% packet loss
round-trip min/avg/max/stddev = 4.568/6.005/7.594/1.122 ms

6. Docker のトラブルシューティング

Docker コンテナを終了した場合

bash のプロンプトが表示された場合は、実行中かどうかを確認し、必要に応じて再起動または再入力する必要があります。

実行中の Docker コンテナを表示するには:

$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
505fc57ffc72        environment       "bash"              10 minutes ago      Up 10 minutes                           codelab_otsim_ctnr

すべての Docker コンテナ(実行中と停止中の両方)を表示するには:

$ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
505fc57ffc72        environment       "bash"              10 minutes ago      Up 10 minutes                           codelab_otsim_ctnr

いずれかの docker ps コマンドの出力にコンテナ codelab_otsim_ctnr が表示されない場合は、再度コンテナを実行します。

$ docker run --name codelab_otsim_ctnr -it --rm \
   --sysctl net.ipv6.conf.all.disable_ipv6=0 \
   --cap-add=net_admin openthread/environment bash

コンテナが停止している場合(docker ps -a には表示されるが docker ps には表示されない場合)は、再起動します。

$ docker start -i codelab_otsim_ctnr

Docker コンテナがすでに実行されている場合(docker ps に表示)、各ターミナルのコンテナに再接続します。

$ docker exec -it codelab_otsim_ctnr bash

「操作を行えません」というエラー

新しい OpenThread ノードを作成するときに(mknod コマンドを使用して)Operation not permitted エラーが発生した場合は、この Codelab で提供されているコマンドに従って、Docker を root ユーザーとして実行していることを確認してください。この Codelab では、ルートレス モードでの Docker の実行はサポートされていません。

7. 完了

OpenThread を使用して最初の Thread ネットワークをシミュレートしました。お疲れさまでした。

この Codelab では、以下について学びました。

  • OpenThread Simulation Docker コンテナを起動して管理する
  • Thread ネットワークをシミュレートする
  • Thread ノードを認証する
  • OpenThread Daemon を使用して Thread ネットワークを管理する

Thread と OpenThread の詳細については、以下のリファレンスをご覧ください。

または、Docker コンテナで OpenThread Border Router を使用してください。