OpenThread を使用した Thread ネットワークのシミュレート

1. はじめに

26b7f4f6b3ea0700.png

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

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

この Codelab では、シミュレートされたデバイスで Thread ネットワークをシミュレートする手順を説明します。

学習内容

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

必要なもの

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

2. ビルドシステムをセットアップする

Git

この Codelab を完了するには Git が必要です。続行する前に、ダウンロードしてインストールしてください。

インストールが完了したら、お使いの OS の手順に沿って OpenThread をダウンロードしてビルドします。

Mac OS X 用 XCode

Mac OS X に OpenThread をインストールしてビルドするには、XCode が必要です。

XCode をインストールしたら、XCode コマンドライン ツールをインストールします。

$ xcode-select --install

Linux / Mac OS X でビルド

これらのインストール手順は、Ubuntu Server 14.04 LTS および Mac OS X Sierra 10.12.6 でテスト済みです。

OpenThread をインストールします。bootstrap コマンドにより、ツールチェーンがインストールされ、環境が適切に構成されていることを確認します。

$ mkdir -p ~/src
$ cd ~/src
$ git clone --recursive https://github.com/openthread/openthread.git
$ cd openthread
$ ./script/bootstrap

Windows を使用する

Windows を使用する場合は、この Codelab の Docker 版を試してみることをおすすめします。

3. OpenThread アプリケーションをビルドする

インストールが完了したら、OpenThread サンプル アプリケーションをビルドします。この Codelab では、シミュレーションのサンプルを使用します。

$ cd ~/src/openthread
$ ./script/cmake-build simulation

OpenThread Daemon をビルドします。

$ ./script/cmake-build posix -DOT_DAEMON=ON

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

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

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

下図は、基本的な Thread ネットワーク トポロジを示しています。この演習では、緑色の円内の 2 つのノード(Thread Leader と Thread Router)を 1 つの接続でシミュレートします。

6e3aa07675f902dc.png

ノードに ping を実行する

1. Node 1 の起動

openthread ディレクトリに移動し、ot-cli-ftd バイナリを使用して、シミュレートされた Thread デバイスの CLI プロセスを生成します。

$ cd ~/src/openthread
$ ./build/simulation/examples/apps/cli/ot-cli-ftd 1

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

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

1 の引数は、「factory-assigned」の最下位ビットを表すファイル記述子です。シミュレートされたデバイスでは IEEE EUI-64この値は、IEEE 802.15.4 無線エミュレーション用に UDP ポートにバインドする場合にも使用されます(ポート = 9000 + ファイル ディスクリプタ)。この 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 start
Done

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

> state
leader
Done

ノード 1 の Thread インターフェースに割り当てられた 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 = ルーター ロケータ(RLOC)を含む
  • ff:fe00 = エンドポイント識別子(EID)を含まない

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

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

2. Node 2 の起動

新しいターミナルを開き、openthread ディレクトリに移動して CLI プロセスを生成します。これが 2 つ目のシミュレートされた Thread デバイスです。

$ cd ~/src/openthread
$ ./build/simulation/examples/apps/cli/ot-cli-ftd 2

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

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

> dataset networkkey e4344ca17d1dca2a33f064992f31f786
Done
> dataset panid 0xc169
Done

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

> dataset commit active
Done

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

> ifconfig up
Done

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

> thread start
Done

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

> state
child
Done

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

> state
router
Done

ネットワークを確認する

ルーター テーブルを見ると、メッシュ ネットワークを簡単に確認できます。

1. 接続を確認する

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

> rloc16
5800
Done

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

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

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

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

シミュレートされた 2 つの Thread デバイス間の接続を検証します。Node 2 で、Node 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 つのノードをオフラインにしてメッシュ ネットワークをテストします。

Node 1 に戻り、Thread を停止します。

> thread stop
Done

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

> state
router
Done
...
> state
leader
Done

確認したら、終了する前に Thread を停止し、Node 2 を出荷時の設定にリセットします。この演習で使用した Thread ネットワーク認証情報が次の演習に引き継がれないようにするため、出荷時設定へのリセットが行われます。

> thread stop
Done
> factoryreset
>
> exit

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

> factoryreset
>
> exit

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

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

前の演習では、シミュレートされた 2 台のデバイスで Thread ネットワークを設定し、接続を検証しました。ただし、これにより、認証されていない IPv6 リンクローカル トラフィックのみがデバイス間で送受信されます。グローバル IPv6 トラフィックを両者間で(および Thread ボーダー ルーター経由でインターネットに)ルーティングするには、ノードを認証する必要があります。

認証を行うには、1 つのデバイスがコミッショナーとして機能する必要があります。コミッショナーは現在、新しい Thread デバイスの認証サーバーで選ばれており、デバイスがネットワークに接続するために必要なネットワーク認証情報を提供する承認者です。

この演習では、前と同じ 2 ノード トポロジを使用します。認証については、Thread Leader はコミッショナー、Thread Router は Joiner として、

d6a67e8a0d0b5dcb.png

1. ネットワークの作成

前の演習から続行する場合、すでに 2 つのターミナル ウィンドウが開いているはずです。表示されていない場合は、2 つを開いて使用できることを確認します。1 つはノード 1、もう 1 つはノード 2 として動作します。

Node 1 で、CLI プロセスを生成します。

$ cd ~/src/openthread
$ ./build/simulation/examples/apps/cli/ot-cli-ftd 1

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

新しい運用データセットを作成し、それをアクティブなデータセットとして commit して、スレッドを開始します。

> 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 start
Done

数秒待ってから、デバイスがスレッド リーダーになっていることを確認します。

> state
leader
Done

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

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

> commissioner start
Done

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

> commissioner joiner add * J01NME
Done

3. Joiner ロールを開始する

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

$ cd ~/src/openthread
$ ./build/simulation/examples/apps/cli/ot-cli-ftd 2

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

> ifconfig up
Done
> joiner start J01NME
Done

... 確認されるまで数秒お待ちください ...

Join success

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

Node 2 が認証されたので、Thread を開始します。

> thread start
Done

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

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

> state
child
Done
...
> state
router
Done

5. 構成をリセット

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

> thread stop
Done
> factoryreset
>
> exit

factoryreset コマンドの後に > プロンプトが再度表示されるように、enter を数回押す必要がある場合があります。

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

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

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

ot-ctl は、RCP の管理と構成のために ot-daemon が提供する CLI です。これにより、RCP を Thread デバイスによって作成されたネットワークに接続します。

ot-daemon を使用する

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

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

前の演習から続ける場合は、すでに 2 つのターミナル ウィンドウが開いているはずです。3 つ目のウィンドウを開き、この演習に使用できるターミナル ウィンドウが 3 つあることを確認します。

1. Node 1 の起動

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

$ cd ~/src/openthread
$ ./build/simulation/examples/apps/cli/ot-cli-ftd 1

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

新しい運用データセットを作成し、それをアクティブなデータセットとして commit して、スレッドを開始します。

> 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 start
Done

ノード 1 の Thread インターフェースに割り当てられた 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
>

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

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

2. ot-daemon の起動

2 番目のターミナル ウィンドウで、openthread ディレクトリに移動し、RCP ノード(Node 2)の ot-daemon を開始します。-v 詳細フラグを使用してログ出力を表示し、実行中であることを確認し、sudo を使用するようにします。

$ cd ~/src/openthread
$ sudo ./build/posix/src/posix/ot-daemon -v \
    'spinel+hdlc+forkpty://build/simulation/examples/apps/ncp/ot-rcp?forkpty-arg=2'

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

ot-daemon[12463]: Running OPENTHREAD/thread-reference-20200818-1938-g0f10480ed; POSIX; Aug 30 2022 10:55:05
ot-daemon[12463]: Thread version: 4
ot-daemon[12463]: Thread interface: wpan0
ot-daemon[12463]: RCP version: OPENTHREAD/thread-reference-20200818-1938-g0f10480ed; SIMULATION; Aug 30 2022 10:54:10

ターミナルを開いたまま、バックグラウンドで動作させます。ここにはこれ以上コマンドを入力する必要はありません。

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

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

3 つ目のターミナル ウィンドウで、ot-ctl を開始します。

$ sudo ./build/posix/src/posix/ot-ctl
>

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

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

> state
disabled
Done

Node 2 の eui64 を取得して、参加を特定の Joiner に制限します。

> eui64
18b4300000000001
Done

Node 1(最初のターミナル ウィンドウ)でコミッショナーを起動し、参加をその eui64 のみに制限します。

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

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

> ifconfig up
Done
> joiner start J01NME
Done

... 確認されるまで数秒お待ちください ...

Join success

Joiner として、RCP(ノード 2)はコミッショナー(ノード 1)で自身を正常に認証し、Thread Network 認証情報を受け取りました。

Node 2 を Thread ネットワークに参加させます。

> thread start
Done

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

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

> state
child
Done
...
> state
router
Done

5. 接続を検証する

Ctrl+D または exit コマンドを使用し、ホストマシンのコマンドラインから ping6 コマンドで EID を指定してノード 1 に ping して、ot-ctl を終了します。ot-daemon RCP インスタンスが正常に Thread ネットワークに参加して通信している場合、ping は成功します。

$ 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

7. 完了

OpenThread を使用して最初の Thread ネットワークのシミュレートに成功しました。うまくできました。

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

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

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