Thread 邊界路由器 - 雙向 IPv6 連線能力和 DNS 型服務探索

1. 簡介

699d673d05a55535.png

什麼是執行緒邊界路由器?

Thread 是一種 IP 型低功耗網網路通訊協定,可讓裝置間的通訊成為裝置與雲端之間的通訊。執行緒網路可以適應拓撲變更,避免出現單點故障。

Thread 邊界路由器會將 Thread 網路連線至其他 IP 網路,例如 Wi-Fi 或乙太網路。Thread 網路需要邊界路由器才能連線至其他網路。Thread 邊界路由器極少支援下列函式:

  • Thread 和 Wi-Fi/乙太網路之間的雙向 IP 連線。
  • 透過 mDNS (Wi-Fi/乙太網路連結) 和 SRP (使用 Thread 網路) 進行雙向服務探索。
  • 合併 Thread 分區,以透過 IP 為基礎的連結合併的執行緒基礎架構。
  • 外部執行緒佣金 (例如手機) 以便驗證及加入 Thread 裝置至 Thread 網路。

Google 發布的 OpenThread 邊界路由器 (OTBR) 是 Thread 邊界路由器的開放原始碼實作。

建構項目

在這個程式碼研究室中,您將設定 Thread 邊界路由器,並透過邊界路由器將手機連線到 Thread 結束裝置。

課程內容

  • 如何設定 OTBR
  • 如何透過 OTBR 建立 Thread 網路
  • 如何使用 SRP 功能建構 OpenThread CLI 裝置
  • 如何運用 SRP 註冊服務
  • 如何探索及觸及 Thread 端點。

軟硬體需求

  • 一台 Raspberry Pi 3/4 裝置,並具備至少 8 GB 功能的 SD 卡。
  • 2 Nordic Semiconductor nRF52840 開發板
  • 未啟用路由器的 IPv6 路由器廣播防護的 Wi-Fi AP。
  • 搭載 iOS 14 或至少搭載 Android 8.1 的 Android 手機。

2. 設定 OTBR

設定 Raspberry Pi

您可以按照 raspberrypi.org 的操作說明,使用 rpi-imager 工具設定全新的 Raspberry Pi 裝置 (而不是使用工具中的 Raspberry Pi OS 自行下載),您可以自行下載 2021-05-07-raspios-buster-armhf-lite。如要完成本程式碼研究室的手機步驟,你必須將 Raspberry Pi 連線至 Wi-Fi AP。請按照這份指南設定無線連線。使用 SSH 登入 Raspberry Pi 可方便您參閱這裡的操作說明。

取得 OTBR 代碼

登入 GitHub 登入 Raspberry Pi 並複製 ot-br-posix

$ git clone https://github.com/openthread/ot-br-posix.git --depth 1

建構並安裝 OTBR

OTBR 提供兩個指令碼來啟動及設定執行緒邊界路由器:

$ cd ot-br-posix
$ ./script/bootstrap
$ INFRA_IF_NAME=wlan0 ./script/setup

OTBR 會同時支援 Thread 介面和 INFRA_IF_NAME 指定的基礎架構網路介面 (例如 Wi-Fi/乙太網路)。Thread 介面由 OTBR 本身建立,且預設命名為 wpan0,如果未明確指定 INFRA_IF_NAME,基礎架構介面會預設為 wlan0。如果 Raspberry Pi 是透過乙太網路線連接,請指定乙太網路介面名稱 (例如 eth0):

$ INFRA_IF_NAME=eth0 ./script/setup

檢查是否已成功安裝 OTBR:

$ sudo service otbr-agent status
● otbr-agent.service - Border Router Agent
   Loaded: loaded (/lib/systemd/system/otbr-agent.service; enabled; vendor preset: enabled)
   Active: activating (auto-restart) (Result: exit-code) since Mon 2021-03-01 05:43:38 GMT; 2s ago
  Process: 2444 ExecStart=/usr/sbin/otbr-agent $OTBR_AGENT_OPTS (code=exited, status=2)
 Main PID: 2444 (code=exited, status=2)

由於 otbr-agent 服務需要 RCP 方塊才能執行,因此預期不會啟用服務。

重新啟動 Raspberry Pi,讓變更生效。

建構並更新 RCP 韌體

OTBR 支援無線電共同處理器 (RCP) 模式的 15.4 個無線電晶片。在這個模式中,OpenThread 堆疊是在主機端執行,透過 IEEE802.15.4 傳輸器傳輸/接收影格。

按照使用 nRF52840 面板和 OpenThread 程式碼研究室的步驟 4 來建構並更新 nRF52840 RCP 裝置:

$ script/build nrf52840 USB_trans

啟動 OTBR 並驗證狀態

將 nRF52840 白板連接至 Raspberry Pi 並啟動 otbr-agent 服務:

$ sudo service otbr-agent restart

確認 otbr-agent 服務已啟用:

$ sudo service otbr-agent status
● otbr-agent.service - Border Router Agent
   Loaded: loaded (/lib/systemd/system/otbr-agent.service; enabled; vendor preset: enabled)
   Active: active (running) since Mon 2021-03-01 05:46:26 GMT; 2s ago
 Main PID: 2997 (otbr-agent)
    Tasks: 1 (limit: 4915)
   CGroup: /system.slice/otbr-agent.service
           └─2997 /usr/sbin/otbr-agent -I wpan0 -B wlan0 spinel+hdlc+uart:///dev/ttyACM0

Mar 01 05:46:26 raspberrypi otbr-agent[2997]: Stop publishing service
Mar 01 05:46:26 raspberrypi otbr-agent[2997]: [adproxy] Stopped
Mar 01 05:46:26 raspberrypi otbr-agent[2997]: PSKc is not initialized
Mar 01 05:46:26 raspberrypi otbr-agent[2997]: Check if PSKc is initialized: OK
Mar 01 05:46:26 raspberrypi otbr-agent[2997]: Initialize OpenThread Border Router Agent: OK
Mar 01 05:46:26 raspberrypi otbr-agent[2997]: Border router agent started.
Mar 01 05:46:26 raspberrypi otbr-agent[2997]: [INFO]-CORE----: Notifier: StateChanged (0x00038200) [NetData PanId NetName ExtPanId]
Mar 01 05:46:26 raspberrypi otbr-agent[2997]: [INFO]-PLAT----: Host netif is down

3. 建立 Thread 網路

ot-ctl 指令可用來控制 otbr-agent 服務。ot-ctl 可接受所有 OpenThread CLI 指令,詳情請參閱 OpenThread CLI 指南

使用 OTBR 建立 Thread 網路:

$ sudo ot-ctl dataset init new
Done
$ sudo ot-ctl dataset commit active
Done
$ sudo ot-ctl ifconfig up
Done
$ sudo ot-ctl thread start
Done

請等待幾秒鐘,系統應該可以看到 OTBR 是 Thread 的 leader,且 Thread 網路資料中有一個 off-mesh-routable (OMR) 前置字元:

$ sudo ot-ctl state
leader
Done
$ sudo ot-ctl netdata show
Prefixes:
Prefixes:
fd76:a5d1:fcb0:1707::/64 paos med 4000
Routes:
fd49:7770:7fc5:0::/64 s med 4000
Services:
44970 5d c000 s 4000
44970 01 9a04b000000e10 s 4000
Done
$ sudo ot-ctl ipaddr      
fda8:5ce9:df1e:6620:0:ff:fe00:fc11
fda8:5ce9:df1e:6620:0:0:0:fc38
fda8:5ce9:df1e:6620:0:ff:fe00:fc10
fd76:a5d1:fcb0:1707:f3c7:d88c:efd1:24a9
fda8:5ce9:df1e:6620:0:ff:fe00:fc00
fda8:5ce9:df1e:6620:0:ff:fe00:4000
fda8:5ce9:df1e:6620:3593:acfc:10db:1a8d
fe80:0:0:0:a6:301c:3e9f:2f5b
Done

4. 設定 SRP 用戶端裝置

建構並刷新 OT CLI

按照「使用 nRF52840 白板和 OpenThread」程式碼研究室的步驟 5 來建構並更新 nRF52840 CLI 結束裝置。

然而,CLI 節點需要 OT_SRP_CLIENTOT_ECDSA 功能,而不是啟用 OT_COMMISSIONEROT_JOINER

因此完整的建構叫用應如下所示:

$ script/build nrf52840 USB_trans -DOT_SRP_CLIENT=ON -DOT_ECDSA=ON

加入 OTBR 網路

如要加入 otbr-agent 服務建立的 Thread 網路,我們必須從 OTBR 裝置取得有效作業資料集。請返回 otbr-agent 指令列並取得使用中的資料集:

$ sudo ot-ctl dataset active -x
0e080000000000010000000300001235060004001fffe002083d3818dc1c8db63f0708fda85ce9df1e662005101d81689e4c0a32f3b4aa112994d29692030f4f70656e5468726561642d35326532010252e204103f23f6b8875d4b05541eeb4f9718d2f40c0302a0ff
Done

返回 SRP 用戶端節點螢幕工作階段,並設定使用中的資料集:

> dataset set active 0e080000000000010000000300001235060004001fffe002083d3818dc1c8db63f0708fda85ce9df1e662005101d81689e4c0a32f3b4aa112994d29692030f4f70656e5468726561642d35326532010252e204103f23f6b8875d4b05541eeb4f9718d2f40c0302a0ff
Done

接著,啟動 Thread 介面:

> ifconfig up
Done
> thread start
Done

等待幾秒鐘,並確認 Thread 網路是否成功執行:

> state
child
Done
> netdata show
Prefixes:
fd76:a5d1:fcb0:1707::/64 paos med 4000
Routes:
fd49:7770:7fc5:0::/64 s med 4000
Services:
44970 5d c000 s 4000
44970 01 9a04b000000e10 s 4000
Done
> ipaddr
fd76:a5d1:fcb0:1707:d3dc:26d3:f70b:b927
fda8:5ce9:df1e:6620:0:ff:fe00:4001
fda8:5ce9:df1e:6620:ed74:123:cc5d:74ba
fe80:0:0:0:d4a9:39a0:abce:b02e
Done

請確認網路資料與 OTBR 上列印的網路資料相符。我們現在可以對 OTBR 的 OMR 位址進行連線偵測 (ping):

> ping fd76:a5d1:fcb0:1707:f3c7:d88c:efd1:24a9
Done
> 16 bytes from fd76:a5d1:fcb0:1707:f3c7:d88c:efd1:24a9: icmp_seq=1 hlim=64 time=49ms

5. 在端對端裝置上發布服務

mDNS 已經常使用 mDNS 發布 DNS-SD 服務。但是,多點傳送訊息會耗用過多頻寬,也會耗盡低功耗電池的電力。Thread 會透過 unicast SRP 通訊協定在 Border 路由器註冊服務,並仰賴邊界路由器,透過 Wi-Fi 或乙太網路連結宣傳服務。

您可以使用 srp client 指令註冊服務。

前往 SRP 用戶端節點畫面工作階段,並自動啟動 SRP 用戶端:

> srp client autostart enable
Done

設定要在 Wi-Fi/乙太網路連結宣傳的主機名稱:

> srp client host name ot-host
Done

如果裝置的 Wi-Fi/乙太網路連結連線到 Thread 結束裝置,則必須宣傳該裝置的 OMR 位址:

> srp client host address fd76:a5d1:fcb0:1707:d3dc:26d3:f70b:b927
Done

最後,請註冊假的 _ipps._tcp 服務:

> srp client service add ot-service _ipps._tcp 12345
Done

稍候片刻,系統應會顯示註冊的服務:

> srp client service
instance:"ot-service", name:"_ipps._tcp", state:Registered, port:12345, priority:0, weight:0
Done

所有設定工作皆已完成,且「_ipps._tcp」服務應已透過 Wi-Fi/乙太網路連結進行宣傳。現在就開始探索並觸及裝置吧!

6. 探索服務

使用手機探索服務

54a136a8940897cc.png

我們使用服務瀏覽器應用程式,透過 Android 手機探索 mDNS 服務,您也可以在 iOS 行動裝置上找到對應的應用程式。開啟應用程式,畫面上隨即會顯示 _ipps._tcp 服務。

使用 Linux 主機探索服務

如果您想從其他 Linux 主機探索服務,可以使用 avahi-browse 指令。

安裝 avahi-daemonavahi-utils

$ sudo apt-get install -y avahi-daemon avahi-utils

解析服務:

$ sudo service avahi-daemon start # Ensure the avahi daemon is started.
$ avahi-browse -r _ipps._tcp
+ wlan0 IPv6 ot-service                                    Secure Internet Printer local
= wlan0 IPv6 ot-service                                    Secure Internet Printer local
   hostname = [ot-host.local]
   address = [fd76:a5d1:fcb0:1707:d3dc:26d3:f70b:b927]
   port = [12345]
   txt = []
...

使用 macOS 主機探索服務

您可以在 macOS 上使用 dns-sd 來解析服務:

$ dns-sd -Z _ipps._tcp local.
Browsing for _ipps._tcp.local.
DATE: ---Sun 14 Mar 2021---
21:31:42.125  ...STARTING...

; To direct clients to browse a different domain, substitute that domain in place of '@'
lb._dns-sd._udp                                 PTR     @

; In the list of services below, the SRV records will typically reference dot-local Multicast DNS names.
; When transferring this zone file data to your unicast DNS server, you'll need to replace those dot-local
; names with the correct fully-qualified (unicast) domain name of the target host offering the service.

_ipps._tcp                                      PTR     ot-service._ipps._tcp
ot-service._ipps._tcp                           SRV     0 0 12345 ot-host.local. ; Replace with unicast FQDN of target host
ot-service._ipps._tcp                           TXT     ""
...

7. 對結束裝置的連線偵測 (ping)

從手機連線偵測

以 Pixel 手機為例,你可以在服務瀏覽器應用程式的服務執行個體詳細資料頁面中,找出先前註冊的服務「ot-service」的 OMR 位址。

bb992962e68d250b.png 888daa1df1e1a9bf.png

我們現在可以使用其他 Network Analyzer 應用程式對 OMR 位址進行連線偵測 (ping)。

很抱歉,Network Analyzer 應用程式的 Android 版本不支援連線偵測 (ping) 公用程式的 mDNS 查詢,也無法直接對主機名稱 ot-host.local 進行連線偵測 (ping),因此我們可以使用 iOS 版的應用程式版本進行連線偵測 (ping)。

從 Linux/macOS 主機進行連線偵測 (ping)

Thread 邊界路由器會透過 Wi-Fi/乙太網路連結,傳送 ICMPv6 路由器廣告 (RA) 至前置字串 (透過前置字串資訊選項) 和路徑 (透過路徑資訊選項) 通告。

準備 Linux 主機

請務必確認您的主機已啟用 RA 和 RIO:

  1. 如果未啟用 IP 轉送功能,net.ipv6.conf.wlan0.accept_ra 應至少為 1,否則為 2
  2. net.ipv6.conf.wlan0.accept_ra_rt_info_max_plen」不得小於 64

在大多數發行情況下,accept_ra 的預設值為 1。不過,其他網路 Daemon 會覆寫這個選項 (例如:Rabberry Pi 中的 dhcpcd 會覆寫 accept_ra0)。你可以透過以下方式檢查 accept_ra 值:

$ sudo sysctl -n net.ipv6.conf.wlan0.accept_ra
0

然後將值設為 1 (如果已啟用 IP 轉送功能,則設為 2):

$ sudo sysctl -w net.ipv6.conf.wlan0.accept_ra=1
Net.ipv6.conf.wlan0.accept_ra = 1

在大部分的 Linux 發行版本中,accept_ra_rt_info_max_plen 選項會預設為 0,並將其設為 64

$ sudo sysctl -w net.ipv6.conf.wlan0.accept_ra_rt_info_max_plen=64
net.ipv6.conf.wlan0.accept_ra_rt_info_max_plen = 64

重新啟動主機後,這項變更將會遺失。例如,將指令附加至 /etc/sysctl.conf 即可永久啟用 RIO:

$ net.ipv6.conf.wlan0.accept_ra_rt_info_max_plen = 64

但由於這些 OTBR 已經在傳送 RA 訊息,以及兩則來路不明的 RA 訊息之間的間隔時間長達數百百秒,因此可能無法更改這些設定。其中一個方法是先中斷 Wi-Fi 連線,再重新與 Wi-Fi 連線,以便傳送路由器招攬訊息,OTBR 也會透過請求的 RA 回應。另一個方法是在邊界路由器上重新啟動邊界轉送函式:

$ sudo ot-ctl br disable
Done
$ sudo ot-ctl br enable
Done

如要重新連線 Wi-Fi 或重新啟動乙太網路介面,請確認 dhcpcd 並未用於管理你的 Wi-Fi/乙太網路 IPv6 網路。因為每次重新啟動介面時,ddefpc 一律會覆寫 accept_ra 選項,而 accept_ra 設定也會遺失。將下列幾行內容附加至 dhcpcd 設定檔 (例如 /etc/dhcpcd.conf),並明確在 dhcpcd 中停用 IPv6:

noipv6
noipv6rs

必須重新啟動,變更才會生效。

準備 macOS 主機

根據預設,系統會啟用這兩個 accept_ra* 選項,但您必須將系統升級至至少 macOS Big Sur。

對主機名稱或 IPv6 位址進行連線偵測 (ping)

我們現在可以使用 ping -6 指令 (透過 macOS 的 ping6) 連線偵測主機名稱 ot-host.local

$ ping -6 ot-host.local.
PING ot-host.local.(fd76:a5d1:fcb0:1707:d3dc:26d3:f70b:b927 (fd76:a5d1:fcb0:1707:d3dc:26d3:f70b:b927)) 56 data bytes
64 bytes from fd76:a5d1:fcb0:1707:d3dc:26d3:f70b:b927 (fd76:a5d1:fcb0:1707:d3dc:26d3:f70b:b927): icmp_seq=1 ttl=63 time=170 ms
64 bytes from fd76:a5d1:fcb0:1707:d3dc:26d3:f70b:b927 (fd76:a5d1:fcb0:1707:d3dc:26d3:f70b:b927): icmp_seq=2 ttl=63 time=64.2 ms
64 bytes from fd76:a5d1:fcb0:1707:d3dc:26d3:f70b:b927 (fd76:a5d1:fcb0:1707:d3dc:26d3:f70b:b927): icmp_seq=3 ttl=63 time=22.8 ms
64 bytes from fd76:a5d1:fcb0:1707:d3dc:26d3:f70b:b927 (fd76:a5d1:fcb0:1707:d3dc:26d3:f70b:b927): icmp_seq=4 ttl=63 time=37.7 ms
64 bytes from fd76:a5d1:fcb0:1707:d3dc:26d3:f70b:b927 (fd76:a5d1:fcb0:1707:d3dc:26d3:f70b:b927): icmp_seq=5 ttl=63 time=28.7 ms
...

這個指令可能會在 Linux 主機上出現 "Name or service not known" 錯誤。這是因為 ping 指令無法用 mDNS 查詢解析 ot-host.local. 名稱。開啟 /etc/nsswitch.conf,然後在 hosts 行中新增 mdns6_minimal

hosts:          files mdns4_minimal mdns6_minimal dns

當然,您可以隨時對 IPv6 位址進行連線偵測 (ping):

$ ping -6 fd76:a5d1:fcb0:1707:d3dc:26d3:f70b:b927
PING fd76:a5d1:fcb0:1707:d3dc:26d3:f70b:b927(fd76:a5d1:fcb0:1707:d3dc:26d3:f70b:b927) 56 data bytes
64 bytes from fd76:a5d1:fcb0:1707:d3dc:26d3:f70b:b927: icmp_seq=1 ttl=63 time=32.9 ms
64 bytes from fd76:a5d1:fcb0:1707:d3dc:26d3:f70b:b927: icmp_seq=2 ttl=63 time=27.8 ms
64 bytes from fd76:a5d1:fcb0:1707:d3dc:26d3:f70b:b927: icmp_seq=3 ttl=63 time=29.9 ms
64 bytes from fd76:a5d1:fcb0:1707:d3dc:26d3:f70b:b927: icmp_seq=4 ttl=63 time=73.5 ms
64 bytes from fd76:a5d1:fcb0:1707:d3dc:26d3:f70b:b927: icmp_seq=5 ttl=63 time=26.4 ms
...

8. 結束裝置發布服務

如要移除從 SRP 用戶端節點註冊的地址和服務,請按照下列步驟操作:

> srp client host remove
Done

無法立即探索 _ipps._tcp 服務。

9. 恭喜

恭喜!您已成功設定 OTBR 做為 Thread 邊界路由器,為 Thread 端對端裝置提供雙向 IP 連線和服務探索功能。

後續步驟

查看一些程式碼研究室…

參考文件