线程边界路由器 - Thread 1.2 多播

1. 简介

608c4c35050eb280.png

什么是 Thread?

Thread 是基于 IP 的低功耗无线网状网络协议,支持设备到设备和设备到云的安全通信。线程网络可以适应拓扑变化,以避免单点故障。

什么是 OpenThread?

Google 发布的 OpenThread 是 Thread® 的开源实现。

什么是 OpenThread 边界路由器?

Google 发布的 OpenThread Border Router (OTBR) 是 Thread Border Router 的开源实现。

Thread 1.2 多播

Thread 1.2 定义了一系列功能,用于支持跨异域网络(Thread 和 Wi-Fi/以太网网络段)进行多播地址,以便范围超过网域本地的多播地址。

Thread 1.2 边界路由器会注册其主干路由器 (BBR) 数据集,而所选 BBR 服务是主要主干路由器 (PBBR),负责多播入站/出站。

Thread 1.2 设备发送 CoAP 消息,以将多播地址注册到 PBBR(多播监听器注册,简称 MLR),前提是该地址大于 Realm 本地。PBBR 在其外部接口上使用 MLDv2 代表其本地 Thread Network 向更广泛的 IPv6 LAN/WAN 传达需要监听的 IPv6 多播组。并且仅当目标至少由一个 Thread 设备订阅时,PBBR 才会将多播流量转发到 Thread 网络。

对于 Thread 1.2 最小端设备,他们可能会依赖其父级来汇总多播地址并代表他们运行 MLR,或者如果其父级是 Thread 1.1,则自行注册。

如需了解详情,请参阅线程数 1.2 规范第 5.24 节:针对 Realm-Local 作用域的多播转发

构建内容

在此 Codelab 中,您将设置一个线程边界路由器和两个 Thread 设备,然后在 Thread 设备和 Wi-Fi 设备上启用和验证多播功能。

学习内容

  • 如何使用 Thread 1.2 多播功能构建 nRF52840 固件。
  • 如何在 Thread 设备上订阅 IPv6 多播地址。

所需条件

  • 一台 Raspberry Pi 3/4 设备和一张容量不低于 8 GB 的 SD 卡。
  • 3 款北欧半导体 nRF52840 DK 开发板。
  • 路由器上未启用 IPv6 路由器通告保护的 Wi-Fi AP。
  • 安装 Python3 的 Linux/macOS 笔记本电脑(Raspberry Pi 也适用)。

2. 设置 OTBR

按照线程边界路由器 - 双向 IPv6 连接和 DNS 服务发现 Codelab 中的说明,在 Raspberry Pi 上设置线程边界路由器。

完成后,Raspberry Pi 应该会创建一个有效的 Thread 网络并连接到 Wi-Fi 网络。

OTBR 应该会在几秒钟内成为主骨干路由器。

$ sudo ot-ctl bbr state
Primary
Done
$ sudo ot-ctl bbr
BBR Primary:
server16: 0xD800
seqno:    23
delay:    1200 secs
timeout:  3600 secs
Done

3. 构建和刷写线程设备

使用多播构建 Thread 1.2 CLI 应用,并刷写两个 nRF52840 DK 开发板。

构建 nRF52840 DK 固件

按照说明克隆项目并构建 nRF52840 固件。

$ mkdir -p ~/src
$ cd ~/src
$ git clone --recurse-submodules --depth 1 https://github.com/openthread/ot-nrf528xx.git
$ cd ot-nrf528xx/
$ script/build nrf52840 USB_trans -DOT_MLR=ON -DOT_THREAD_VERSION=1.2
$ arm-none-eabi-objcopy -O ihex build/bin/ot-cli-ftd ot-cli-ftd.hex

我们可以在 ot-cli-ftd.hex 中找到已成功构建的十六进制固件。

闪光灯 nRF52840 DK 固件

使用 nRF 命令行工具中的 nrfjprog 将固件刷写到 nRF52840 DK。

$ nrfjprog -f nrf52 --chiperase --program ot-cli-ftd.hex --reset

4. 将 Thread 设备附加到 Thread 网络

OTBR 在前面的步骤中创建了一个 Thread 网络。我们现在可以将 nRF52840 DK 添加到 Thread 网络:

从 OTBR 获取原始活跃数据集:

$ sudo ot-ctl dataset active -x
0e080000000000000000000300000b35060004001fffc00208dead00beef00cafe0708fddead00beef00000510e50d3d0931b3430a59c261c684585a07030a4f70656e54687265616401022715041021cf5e5f1d80d2258d5cfd43416525e90c0302a0ff

连接到 nRF52840 DK 开发板:

$ screen /dev/ttyACM0 115200

为 nRF52840 DK 配置活动数据集:

> dataset set active 0e080000000000000000000300000b35060004001fffc00208dead00beef00cafe0708fddead00beef00000510e50d3d0931b3430a59c261c684585a07030a4f70656e54687265616401022715041021cf5e5f1d80d2258d5cfd43416525e90c0302a0ff
Done

启动线程堆栈并等待几秒钟,并验证设备是否已成功连接:

> ifconfig up
Done
> thread start
Done
> state
child

重复上述步骤,将其他 nRF52840 DK 开发板连接到 Thread 网络。

我们现已成功设置 3 个 Thread 设备:OTBR 和 2 个 nRF52840 DK 开发板。

5. 设置 Wi-Fi 网络

在 OTBR 和笔记本电脑上设置 Wi-Fi 网络,确保它们连接到同一个 Wi-Fi AP。

我们可以使用 raspi-config 在 Raspberry Pi OTBR 上设置 Wi-Fi SSID 和口令。

最终网络拓扑如下所示:

5d0f36fd69ebcc9a.png

6. 订阅 IPv6 多播地址

在 nRF52840 最终设备 1 上订阅 ff05::abcd

> ipmaddr add ff05::abcd
Done

验证 ff05::abcd 是否已成功订阅:

> ipmaddr
ff33:40:fdde:ad00:beef:0:0:1
ff32:40:fdde:ad00:beef:0:0:1
ff05:0:0:0:0:0:0:abcd            <--- ff05::abcd subscribed
ff02:0:0:0:0:0:0:2
ff03:0:0:0:0:0:0:2
ff02:0:0:0:0:0:0:1
ff03:0:0:0:0:0:0:1
ff03:0:0:0:0:0:0:fc
Done

在笔记本电脑上订阅 ff05::abcd

我们需要 Python 脚本 subscribe6.py 以在笔记本电脑上订阅多播地址。

复制下面的代码并将其另存为 subscribe6.py

import ctypes
import ctypes.util
import socket
import struct
import sys

libc = ctypes.CDLL(ctypes.util.find_library('c'))
ifname, group = sys.argv[1:]
addrinfo = socket.getaddrinfo(group, None)[0]
assert addrinfo[0] == socket.AF_INET6
s = socket.socket(addrinfo[0], socket.SOCK_DGRAM)
group_bin = socket.inet_pton(addrinfo[0], addrinfo[4][0])
interface_index = libc.if_nametoindex(ifname.encode('ascii'))
mreq = group_bin + struct.pack('@I', interface_index)
s.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_JOIN_GROUP, mreq)
print("Subscribed %s on interface %s." % (group, ifname))
input('Press ENTER to quit.')

运行 subscribe6.py 以便为 Wi-Fi 网络接口(例如 wlan0)订阅 ff05::abcd

$ sudo python3 subscribe6.py wlan0 ff05::abcd
Subscribed ff05::abcd on interface wlan0.
Press ENTER to quit.

采用多播订阅的最终网络拓扑如下所示:

b118448c98b2d583.png

现在,我们已经在 Thread 网络中的 nRF52840 最终设备 1 和 Wi-Fi 网络中的笔记本电脑上订阅了 IPv6 多播地址,接下来我们将验证以下部分中双向 IPv6 多播的可达性。

7. 验证入站 IPv6 多播

现在,我们应该可以通过 Wi-Fi 网络中的 IPv6 多播地址 ff05::abcd,同时访问 Thread 网络中的 nRF52840 最终设备 1 和笔记本电脑。

通过 WLAN 接口在 OTBR 上 ping ff05::abcd

$ ping -6 -b -t 5 -I wlan0 ff05::abcd
PING ff05::abcd(ff05::abcd) from 2401:fa00:41:801:83c1:a67:ae22:5346 wlan0: 56 data bytes
64 bytes from fdb5:8d36:6af9:7669:e43b:8e1b:6f2a:b8fa: icmp_seq=1 ttl=64 time=57.4 ms
64 bytes from 2401:fa00:41:801:8c09:1765:4ba8:48e8: icmp_seq=1 ttl=64 time=84.9 ms (DUP!)
64 bytes from fdb5:8d36:6af9:7669:e43b:8e1b:6f2a:b8fa: icmp_seq=2 ttl=64 time=54.8 ms
64 bytes from 2401:fa00:41:801:8c09:1765:4ba8:48e8: icmp_seq=2 ttl=64 time=319 ms (DUP!)
64 bytes from fdb5:8d36:6af9:7669:e43b:8e1b:6f2a:b8fa: icmp_seq=3 ttl=64 time=57.5 ms
64 bytes from 2401:fa00:41:801:8c09:1765:4ba8:48e8: icmp_seq=3 ttl=64 time=239 ms (DUP!)

# If using MacOS, use this command. The interface is typically not "wlan0" for Mac.
$ ping6 -h 5 -I wlan0 ff05::abcd

我们可以看到,OTBR 可以从 nRF52840 最终用户设备 1 和笔记本电脑收到两条 ping 回复,因为它们同时订阅了 ff05::abcd。这表示 OTBR 可以将 IPv6 Ping 请求多播数据包从 Wi-Fi 网络转发到 Thread 网络。

8. 验证出站 IPv6 多播

ping ff05::abcd on nRF52840 End Device 2

> ping ff05::abcd 100 10 1
108 bytes from fdb5:8d36:6af9:7669:e43b:8e1b:6f2a:b8fa: icmp_seq=12 hlim=64 time=297ms
108 bytes from 2401:fa00:41:801:64cb:6305:7c3a:d704: icmp_seq=12 hlim=63 time=432ms
108 bytes from fdb5:8d36:6af9:7669:e43b:8e1b:6f2a:b8fa: icmp_seq=13 hlim=64 time=193ms
108 bytes from 2401:fa00:41:801:64cb:6305:7c3a:d704: icmp_seq=13 hlim=63 time=306ms
108 bytes from fdb5:8d36:6af9:7669:e43b:8e1b:6f2a:b8fa: icmp_seq=14 hlim=64 time=230ms
108 bytes from 2401:fa00:41:801:64cb:6305:7c3a:d704: icmp_seq=14 hlim=63 time=279ms

nRF52840 最终用户设备 2 可以接收来自 nRF52840 终端设备 1 和笔记本电脑的 ping 回复。这表示 OTBR 可以将 IPv6 Ping 回复多播软件包从 Thread 网络转发到 Wi-Fi 网络。

9. 恭喜

恭喜!您已成功设置线程边界路由器和已验证双向 IPv6 多播。

如需详细了解 OpenThread,请访问 openthread.io

参考文档: