在 Docker 中使用 OpenThread 模擬 Thread 網路

1. 簡介

26b7f4f6b3ea0700.png

Google 發布的 OpenThreadThread 網路通訊協定的開放原始碼實作項目。Google Nest 已推出 OpenThread,讓開發人員能夠更廣泛地運用 Nest 產品所用的技術,加速為智慧聯網家庭開發產品。

Thread 規格定義了用於家用應用程式的 IPv6 穩定、安全和低功率無線裝置對通訊通訊協定。OpenThread 實作所有 Thread 網路層,包括 IPv6、6LoWPAN、IEEE 802.15.4 以及 MAC 安全性、網格連結建立和網格轉送。

本程式碼研究室將逐步說明如何使用 Docker 模擬裝置的 Thread 網路。

課程內容

  • 如何設定 OpenThread 建構工具鍊
  • 如何模擬 Thread 網路
  • 如何驗證 Thread 節點
  • 如何使用 OpenThread Daemon 管理 Thread 網路

軟硬體需求

  • Docker
  • Linux 網路轉送的基本知識

2. 設定 Docker

本程式碼研究室旨在在 Linux、Mac OS X 或 Windows 電腦上使用 Docker。建議使用 Linux 環境。

安裝 Docker

在您選擇的作業系統上安裝 Docker。

提取 Docker 映像檔

安裝 Docker 後,請開啟終端機視窗並提取 openthread/environment Docker 映像檔。這個映像檔包含預先建構的 OpenThread 和 OpenThread Daemon,已可用於這個程式碼研究室。

$ 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

--rm 選項會在容器關閉時刪除容器。如果您不希望刪除容器,請勿使用這個選項。

記下本程式碼研究室所需的標記:

  • --sysctl net.ipv6.conf.all.disable_ipv6=0:這會在容器中啟用 IPv6
  • --cap-add=net_admin — 啟用 NET_ADMIN 功能,方便您執行網路相關作業,例如新增 IP 路徑

進入容器後,畫面上應會顯示類似下列提示:

root@c0f3912a74ff:/#

在上述範例中,c0f3912a74ff 是容器 ID。Docker 容器執行個體的容器 ID 與本程式碼研究室的提示訊息不同。

使用 Docker

本程式碼研究室假設您熟悉使用 Docker 的基本概念。應該將整個容器保留在 Docker 容器中。

3. 模擬 Thread 網路

您要用於這個程式碼研究室的應用程式範例將能示範基本的 OpenThread 應用程式,該應用程式可透過基本指令列介面 (CLI) 開啟 OpenThread 設定和管理介面。

這個練習可引導您透過最少模擬執行緒,對其中一個模擬 Thread 裝置進行連線偵測 (ping)。

下圖說明基本的 Thread 網路拓撲。在本練習中,我們會模擬綠色圓圈中的兩個節點:「Thread 領導者」和「Thread 路由器」,每個節點之間只能有一個連線。

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 二進位檔產生模擬執行緒的 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 通訊埠時,也會使用這個值。這個程式碼研究室的每個模擬執行緒裝置都會使用不同的檔案描述元。

注意:產生模擬裝置程序時,僅應使用 1 程式碼研究室所述的檔案描述元。檔案 0 已保留供其他用途使用。

建立新的作業資料集,然後將其提交為使用中的資料集。作業資料集為您建立的 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

將這個資料集提交為使用中的資料集:

> dataset commit active
Done

開啟 IPv6 介面:

> ifconfig up
Done

啟動 Thread 通訊協定作業:

> thread start
Done

等待幾秒鐘,並確認裝置已成為「執行緒領導者」。領導人負責管理路由器 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 = las-local
  • 開頭為 fe80 = link-local

網格的本機地址類型會進一步分類:

  • 包含 ff:fe00 = 路由器定位器 (RLOC)
  • 不包含 ff:fe00 = 端點 ID (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 程序。這是您第二個模擬 Thread 裝置:

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

注意:執行這個指令之後,如果系統未顯示 > 提示,請按下 enter

使用與節點 1 的作業資料集相同的值來設定執行緒網路金鑰和永久帳號 ID:

> dataset networkkey e4344ca17d1dca2a33f064992f31f786
Done
> dataset panid 0xc169
Done

將這個資料集提交為使用中的資料集:

> dataset commit active
Done

開啟 IPv6 介面:

> ifconfig up
Done

啟動 Thread 通訊協定作業:

> thread start
Done

裝置會初始化為子項。Thread Child Child to the End Device (Thread 子項) 屬於 Thread 裝置,這類裝置只能透過父項裝置傳輸及接收單聲道流量。

> state
child
Done

2 分鐘內,您應該會看到狀態從 child 切換為 router。Thread 路由器能夠在 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 連線偵測 (ping) 1 節點

驗證兩個模擬 Thread 裝置之間的連線。在節點 2 中,ping 已指派給節點 1 的 EID:

> 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 提示。

測試網路

現在,您可以成功在兩個模擬的 Thread 裝置之間進行連線偵測 (ping),只要將一個節點離線,即可測試網格網路。

返回節點 1 並停止執行緒:

> thread stop
Done

切換至節點 2 並查看狀態。節點會在兩個分鐘內偵測到節點 1 (節點 1) 處於離線狀態,因此節點 2 的轉換作業應該會是網路的 leader

> state
router
Done
...
> state
leader
Done

確認後,停止執行緒並恢復原廠設定節點 2,然後再返回 Docker bash 提示。恢復原廠設定是為了確保這個練習中使用的 Thread 網路憑證不會轉移至下一個練習。

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

您可能需要多次按下 enter 鍵,才能在 factoryreset 指令後方顯示 > 提示。請勿退出 Docker 容器。

一併恢復原廠設定並結束節點 1:

> factoryreset
>
> exit
root@c0f3912a74ff:/#

請參閱 OpenThread CLI 參考資料,探索所有可用的 CLI 指令。

4. 使用委託功能驗證節點

在先前的練習中,您將設定 Thread 網路,其中包含兩部模擬裝置並驗證連線。不過,這樣也不需要在裝置之間傳遞未經驗證的 IPv6 連結本機流量。如要在節點之間傳輸全域 IPv6 流量 (和透過 Thread 邊界路由器的網際網路),您必須驗證節點。

如要進行驗證,其中一部裝置必須擔任佣金。開發運作人員是目前針對 Thread 裝置選擇的驗證伺服器,以及提供裝置加入網路所需的網路憑證的授權者。

在本練習中,我們會使用與先前相同的兩個節點拓撲。如要進行驗證,Thread 領導者須擔任協調者 (Thread 路由器),

d6a67e8a0d0b5dcb.png

Docker

針對左側練習中的所有節點 (終端機視窗),請務必使用 OpenThread 版本執行 Docker 容器。如果接續先前的練習,您仍應在同一個 Docker 容器中開啟兩個 bash 提示。如果不是,請參閱 Docker 疑難排解步驟,或重新執行 Simulate Thread 網路 練習。

1. 建立網路

在節點 1 中,產生 CLI 程序:

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

注意:執行這個指令之後,如果系統未顯示 > 提示,請按下 enter

建立新的作業資料集,並將其做為使用中的資料集,然後啟動 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

將這個資料集提交為使用中的資料集:

> dataset commit active
Done

開啟 IPv6 介面:

> ifconfig up
Done

啟動 Thread 通訊協定作業:

> thread start
Done

等待數秒,並確認裝置已成為執行緒領導者:

> state
leader
Done

2. 開始執行委員會角色

在節點 1 上,啟動佣金委員會角色:

> commissioner start
Done

允許任何彙整者 (使用 * 萬用字元) 與 J01NME 彙整憑證建立關係至網路。加入人員是指由管理員管理員新增至佣金 (Thread 網路) 的裝置。

> commissioner joiner add * J01NME
Done

3. 啟動「彙整者」角色

在第二個終端機視窗中,在 Docker 容器中產生新的 CLI 程序。這是節點 2。

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

在節點 2 中,使用 J01NME 彙整憑證啟用 Shared 角色。

> ifconfig up
Done
> joiner start J01NME
Done

... 請稍候幾秒鐘,以確認一下 ...

Join success

做為彙整器,裝置 (Node 2) 已通過歐盟委員會 (Node 1) 驗證,並收到 Thread 網路憑證。

現在,節點 2 已通過驗證,請啟動 Thread:

> thread start
Done

4. 驗證網路驗證

檢查節點 2 上的 state,確認其現已加入網路。節點會在兩個分鐘內從 child 轉換至 router

> state
child
Done
...
> state
router
Done

5. 重新設定

如要準備下一個運動,請重設設定。在每個節點上停止執行緒,恢復原廠設定,然後結束模擬的 Thread 裝置:

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

您可能需要多次按下 enter 鍵,才能在 factoryreset 指令後方顯示 > 提示。

5. 使用 OpenThread Daemon 管理網路

在本練習中,我們會模擬一個 CLI 執行個體 (單一嵌入式 SoC Thread 裝置) 和一個無線電 Co-Processor (RCP) 執行個體。

ot-daemon 是 OpenThread Posix 應用程式的模式,使用 UNIX 通訊端做為輸入和輸出,讓 OpenThread 核心能以服務的形式執行。用戶端可以透過 OpenThread CLI 做為通訊協定連線至通訊端,以與這項服務通訊。

ot-ctlot-daemon 提供的 CLI,用於管理及設定 RCP。藉此將 RCP 連線至 Thread 裝置所建立的網路。

Docker

針對本練習中的每個節點 (終端機視窗),請務必使用 OpenThread 版本執行 Docker 容器。如果接續先前的練習,您就應該在同一個 Docker 容器中開啟兩個 bash 提示。否則,請參閱 Docker 疑難排解步驟。

使用 ot-daemon

本練習會使用三個終端機視窗,如下:

  1. 模擬 Thread 裝置的 CLI 執行個體 (節點 1)
  2. ot-daemon 處理節點
  3. ot-ctl CLI 執行個體

1. 啟動節點 1

在第一個終端機視窗中,產生模擬執行緒的 CLI 程序:

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

注意:執行這個指令之後,如果系統未顯示 > 提示,請按下 enter

建立新的作業資料集,並將其做為使用中的資料集,然後啟動 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

將這個資料集提交為使用中的資料集:

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

模擬 Thread 網路 步中所述,一個地址為連結本機 (fe80),而三個位址為網格本機位址 (fd)。EID 是不含網格ff:fe00的網格本機位址。在這個輸出範例中,EID 為 fd55:cf34:dea5:7994:460:872c:e807:c4ab

ipaddr 輸出中找出特定 EID,用於與節點通訊。

2. 啟動 ot-Daemon

在第二個終端機視窗中,建立 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 節點。

開啟第三個終端機視窗,並執行現有的容器:

$ docker exec -it codelab_otsim_ctnr bash

進入容器後,啟動 ot-ctl

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

您將在這個第三個終端機視窗中使用 ot-ctl 管理透過 ot-daemon 的第二個終端機視窗啟動的節點 2 (RCP 節點)。檢查節點 2 的 state

> state
disabled
Done

取得節點 2 的 eui64,限制與特定彙整器的彙整:

> eui64
18b4300000000001
Done

在節點 1 (第一個終端機視窗) 上啟動委員會,並限制只與 eui64 連線:

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

在第三個終端機視窗中,開啟節點 2 的網路介面並加入網路:

> ifconfig up
Done
> joiner start J01NME
Done

... 請稍候幾秒鐘,以確認一下 ...

Join success

作為彙整工具的 RCP (節點 2) 已透過佣金 (Node 1) 成功驗證自身身分,並接收 Thread 網路憑證。

現在將 Node 2 加入 Thread 網路 (同樣在第三個終端機視窗中):

> thread start
Done

4. 驗證網路驗證

在第三個終端機中,檢查節點 2 上的 state,確認其現已加入網路。節點會在兩個分鐘內從 child 轉換至 router

> state
child
Done
...
> state
router
Done

5. 驗證連線

在第三終端機視窗中,使用 Ctrl+Dexit 指令退出 ot-ctl,然後返回容器的 bash 控制台。在這個控制台中,使用節點搭配 ping6 指令使用 EID 連線偵測 1 節點。如果 ot-daemon RCP 執行個體成功加入並與 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 提示:您可能需要檢查是否正在執行,然後視需要重新啟動 / 重新輸入。任何不使用 --rm 選項的 Docker 容器,仍會存在。

如要顯示正在執行的 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

只有在希望在容器關閉時刪除容器時,才使用 --rm 選項。

如果容器已停止 (列在 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 錯誤,請務必根據這個程式碼研究室提供的指令,以超級使用者的身分執行 Docker。這個程式碼研究室不支援在無根模式中執行 Docker。

7. 恭喜!

您已成功使用 OpenThread 模擬第一個 Thread 網路。太棒了!

在本程式碼研究室中,您瞭解如何:

  • 啟動及管理 OpenThread 模擬 Docker 容器
  • 模擬 Thread 網路
  • 驗證 Thread 節點
  • 使用 OpenThread Daemon 管理 Thread 網路

如要進一步瞭解 Thread 和 OpenThread,請參考下列參考資料:

您也可以嘗試使用 Docker 容器中的 OpenThread 邊界路由器