1. 簡介

Google 發布的 OpenThread 是 Thread 網路通訊協定的開放原始碼實作項目。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,會與本程式碼研究室提示中顯示的 ID 不同。
使用 Docker
本程式碼研究室假設您瞭解 Docker 的基本用法。在整個程式碼研究室中,您都應該留在 Docker 容器中。
3. 模擬 Thread 網路
您在本程式碼研究室中使用的範例應用程式,會展示最基本的 OpenThread 應用程式,透過基本指令列介面 (CLI) 公開 OpenThread 設定和管理介面。
本練習會逐步說明從一個模擬的 Thread 裝置 Ping 另一個模擬的 Thread 裝置,所需的最少步驟。
下圖說明基本的 Thread 網路拓撲。在本練習中,我們將模擬綠色圓圈內的兩個節點:Thread Leader 和 Thread Router,兩者之間只有一個連線。

建立網路
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 無線電模擬的 UDP 通訊埠 (通訊埠 = 9000 + 檔案描述元)。本程式碼研究室中的每個模擬 Thread 裝置執行個體都會使用不同的檔案描述元。
注意:如要為模擬裝置產生程序,請只使用本程式碼研究室中註明的 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
稍候幾秒鐘,確認裝置已成為 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= 端點 ID (EID)
在控制台輸出內容中找出 EID,並記下以供日後使用。在上述輸出範例中,EID 為:
fd61:2344:9a52:ede0:d041:c5ba:a7bc:5ce6
2. 啟動節點 2
開啟新的終端機,並在目前執行的 Docker 容器中執行 bash 殼層,以供 Node 2 使用。
$ docker exec -it codelab_otsim_ctnr bash
在這個新的 bash 提示中,使用 2 引數產生 CLI 程序。這是第二個模擬的 Thread 裝置:
root@c0f3912a74ff:/# /openthread/build/examples/apps/cli/ot-cli-ftd 2
注意:執行這項指令後,如果沒有看到 > 提示,請按 enter。
設定 Thread 網路金鑰和 PAN ID,使用與節點 1 作業資料集相同的值:
> dataset networkkey e4344ca17d1dca2a33f064992f31f786 Done > dataset panid 0xc169 Done
將這個資料集做為有效資料集提交:
> dataset commit active Done
啟動 IPv6 介面:
> ifconfig up Done
啟動 Thread 協定作業:
> thread start Done
裝置會初始化為子項裝置。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 的 RLOC 0x5800,確認節點 2 已連上網狀網路。
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:
> thread stop Done
切換至節點 2 並檢查狀態。兩分鐘內,節點 2 會偵測到領導者 (節點 1) 離線,您應該會看到節點 2 轉換為網路的 leader:
> state router Done ... > state leader Done
確認後,請停止 Thread 並將 Node 2 恢復原廠設定,然後返回 Docker bash 提示。恢復原廠設定是為了確保我們在這項練習中使用的 Thread 網路憑證不會沿用至下一個練習。
> thread stop Done > factoryreset > > exit root@c0f3912a74ff:/#
執行 factoryreset 指令後,可能需要按幾次 enter 才能返回 > 提示。請勿結束 Docker 容器。
同時將節點 1 恢復原廠設定並退出:
> factoryreset > > exit root@c0f3912a74ff:/#
如要瞭解所有可用的 CLI 指令,請參閱 OpenThread CLI 參考資料。
4. 使用 Commissioning 驗證節點
在先前的練習中,您設定了 Thread 網路,其中包含兩個模擬裝置,並驗證連線。不過,這只允許未經驗證的 IPv6 連結本機流量在裝置間傳輸。如要在節點之間轉送全球 IPv6 流量 (以及透過 Thread 邊界路由器轉送網際網路流量),必須先驗證節點。
如要進行驗證,其中一部裝置必須擔任 Commissioner。Commissioner 是目前為新 Thread 裝置選定的驗證伺服器,也是提供裝置加入網路所需網路憑證的授權者。
在本練習中,我們將使用與先前相同的雙節點拓撲。進行驗證時,Thread Leader 會做為 Commissioner,Thread Router 則會做為 Joiner。

Docker
在剩餘練習中,請務必為每個節點 (終端機視窗) 執行 OpenThread 建構的 Docker 容器。如果繼續進行上一個練習,您應該仍有兩個 bash 提示在同一個 Docker 容器中開啟。如果沒有,請參閱「Docker 疑難排解」步驟,或直接重新進行「模擬 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
稍候幾秒,確認裝置已成為 Thread 領導者:
> state leader Done
2. 開始擔任委員角色
在節點 1 上啟動 Commissioner 角色:
> commissioner start Done
允許任何加入者 (使用 * 萬用字元) 透過 J01NME 加入者憑證委派至網路。加入者是由管理員新增至已委任的 Thread 網路。
> commissioner joiner add * J01NME Done
3. 啟動 Joiner 角色
在第二個終端機視窗中,於 Docker 容器中產生新的 CLI 程序。這是節點 2。
root@c0f3912a74ff:/# /openthread/build/examples/apps/cli/ot-cli-ftd 2
在節點 2 上,使用 J01NME Joiner Credential 啟用 Joiner 角色。
> ifconfig up Done > joiner start J01NME Done
... 等待幾秒鐘以確認 ...
Join success
身為加入者,裝置 (節點 2) 已成功向管理員 (節點 1) 驗證自身,並收到 Thread 網路憑證。
Node 2 驗證完成後,請啟動 Thread:
> thread start Done
4. 驗證網路驗證
檢查節點 2 上的 state,確認節點 2 現在已加入網路。在兩分鐘內,節點 2 會從 child 轉換為 router:
> state child Done ... > state router Done
5. 重新設定
為準備下一個練習,請重設設定。在每個節點上停止執行緒、恢復原廠設定,然後結束模擬的執行緒裝置:
> thread stop Done > factoryreset > > exit root@c0f3912a74ff:/#
執行 factoryreset 指令後,可能需要按幾次 enter 才能返回 > 提示。
5. 使用 OpenThread Daemon 管理網路
在本練習中,我們將模擬一個 CLI 執行個體 (單一嵌入式 SoC Thread 裝置) 和一個無線電共同處理器 (RCP) 執行個體。
ot-daemon 是 OpenThread Posix 應用程式的模式,使用 UNIX Socket 做為輸入和輸出,因此 OpenThread 核心可以做為服務執行。用戶端可以透過 OpenThread CLI 做為通訊協定,連線至通訊端與這項服務通訊。
ot-ctl 是 ot-daemon 提供的 CLI,可管理及設定 RCP。我們將使用這項功能,將 RCP 連線至 Thread 裝置建立的網路。
Docker
在本練習中,請務必為每個節點 (終端機視窗) 執行搭載 OpenThread 建構版本的 Docker 容器。如果從上一個練習繼續操作,您應該已在同一個 Docker 容器中開啟兩個 bash 提示。如果沒有,請參閱「Docker 疑難排解」步驟。
使用 ot-daemon
本練習會使用三個終端機視窗,分別對應下列項目:
- 模擬 Thread 裝置的 CLI 執行個體 (節點 1)
ot-daemon處理節點ot-ctlCLI 執行個體
1. 啟動節點 1
在第一個終端機視窗中,產生模擬 Thread 裝置的 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 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 網路」步驟所述,一個位址是連結本機位址 (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 使用的 CLI 與 OpenThread CLI 應用程式相同。因此,您可以控制 ot-daemon 節點,方式與其他模擬的 Thread 裝置相同。
開啟第三個終端機視窗,然後執行現有容器:
$ 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,將加入限制在特定 Joiner:
> eui64 18b4300000000001 Done
在節點 1 (第一個終端機視窗) 上啟動 Commissioner,並限制只能加入該 eui64:
> commissioner start Done > commissioner joiner add 18b4300000000001 J01NME Done
在第三個終端機視窗中,開啟節點 2 的網路介面並加入網路:
> ifconfig up Done > joiner start J01NME Done
... 等待幾秒鐘以確認 ...
Join success
身為加入者,RCP (節點 2) 已向 Commissioner (節點 1) 成功驗證自身,並收到 Thread 網路憑證。
現在將節點 2 加入 Thread 網路 (同樣在第三個終端機視窗中):
> thread start Done
4. 驗證網路驗證
在第三個終端機中,檢查節點 2 上的 state,確認節點 2 現在已加入網路。在兩分鐘內,節點 2 會從 child 轉換為 router:
> state child Done ... > state router Done
5. 驗證連線
在第三個終端機視窗中,使用 Ctrl+D 或 exit 指令結束 ot-ctl,然後返回容器的 bash 控制台。從這個控制台使用 ping6 指令,透過節點 1 的 EID ping 節點 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 提示,你可能需要檢查是否正在執行,並視需要重新啟動 / 重新輸入。您建立的任何 Docker 容器 (未使用 --rm 選項) 應該仍存在。
如要顯示正在執行的 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
「不允許的作業」錯誤
使用 mknod 指令建立新的 OpenThread 節點時,如果遇到 Operation not permitted 錯誤,請確認您是按照本 Codelab 提供的指令,以 root 使用者身分執行 Docker。本 Codelab 不支援以無根模式執行 Docker。
7. 恭喜!
您已使用 OpenThread 成功模擬第一個 Thread 網路。太棒了!
在本程式碼研究室中,您學會如何:
- 啟動及管理 OpenThread 模擬 Docker 容器
- 模擬 Thread 網路
- 驗證 Thread 節點
- 使用 OpenThread Daemon 管理 Thread 網路
如要進一步瞭解 Thread 和 OpenThread,請參閱下列參考資料: