1. 简介
什么是线程?
Thread 是一种基于 IP 的低功耗无线网格网络协议,可实现从设备到设备的安全通信,以及设备到云的通信。线程网络可以适应拓扑变化,以避免单点故障。
什么是 OpenThread?
Google 发布的 OpenThread 是 Thread® 的开源实现。
什么是 OpenThread 边界路由器?
Google 发布的 OpenThread Border Router (OTBR) 是线程边界路由器的开源实现。
线程 1.2 多播
线程 1.2 定义了一系列功能,支持通过异构网络(线程和 Wi-Fi/以太网网络分段)对范围大于大领域本地网络的多播地址进行多播。
线程 1.2 边界路由器会注册其骨干路由器 (BBR) 数据集,而选定的 BBR 服务就是主骨干路由器 (PBBR),负责接收多播入站/出站请求。
如果地址大于本地领域,线程 1.2 设备就会发送 CoAP 消息,以将多播地址注册到 PBBR(多播监听器注册 (MLR))。PBBR 在其外部接口上使用 MLDv2,代表其本地线程网络,向更广泛的 IPv6 LAN/WAN 告知需要侦听的 IPv6 多播组。只有在目的地被至少一个线程设备订阅时,PBRB 才会将多播流量转发到线程网络。
对于线程 1.2 最小端设备,它们可能依赖于父项来聚合多播地址并代表他们执行 MLR,或者如果父项是线程 1.1,请自行注册。
如需了解详情,请参阅 Thread 1.2 规范第 5.24 节:大于 Realm-Local 范围的多播转发。
构建内容
在此 Codelab 中,您将设置线程边界路由器和两个线程设备,然后在线程设备和 Wi-Fi 设备上启用和验证多播功能。
学习内容
- 如何使用线程 1.2 多播功能构建 nRF52840 固件。
- 如何在线程设备上订阅 IPv6 多播地址。
所需条件
- Raspberry Pi 3/4 设备和至少 8 GB 功能的 SD 卡。
- 3 台北欧半导体 nRF52840 DK 开发板。
- 未启用路由器的 IPv6 路由器通告防护的 WLAN AP。
- 已安装 Python3 的 Linux/macOS 笔记本电脑(Raspberry Pi 也可运行)。
2. 设置 OTBR
请遵循线程边界路由器 - 双向 IPv6 连接和基于 DNS 的服务发现 用于在 Raspberry Pi 上设置线程边界路由器的 Codelab。
完成后,Raspberry Pi 应该能创建一个正常运行的线程网络并连接到 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.构建和刷写线程设备
使用多播构建线程 1.2 CLI 应用,并刷写两个 nRF52840 DK 板。
build 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
上找到成功构建的 HEX 固件。
Flash nRF52840 DK 固件
使用 nrfjprog
(属于 nRF 命令行工具)将固件刷写到 nRF52840 DK 上。
$ nrfjprog -f nrf52 --chiperase --program ot-cli-ftd.hex --reset
4.将线程设备连接到线程网络
OTBR 已在先前的步骤中创建了线程网络。现在,我们可以将 nRF52840 DK 添加到线程网络中:
从 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 板连接到线程网络。
我们已成功设置包含 3 个线程设备的 Thread 网络:OTBR 和两个 nRF52840 DK 开发板。
5. 设置 Wi-Fi 网络
在 OTBR 和笔记本电脑上设置 Wi-Fi 网络,以便它们连接到同一个 Wi-Fi AP。
我们可以使用 raspi-config 在 Raspberry Pi OTBR 上设置 Wi-Fi SSID 和密码。
最终的网络拓扑如下所示:
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.
包含多播订阅的最终网络拓扑如下所示:
现在,我们已在线程网络中的 nRF52840 最终用户设备 1 上和 Wi-Fi 网络中的笔记本电脑上订阅了 IPv6 多播地址,接下来我们将验证双向 IPv6 多播可达性。
7. 验证入站 IPv6 多播
现在,我们应该能够使用 Wi-Fi 网络中的 IPv6 多播地址 ff05::abcd
连接到线程网络中的 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!)
可以看到,由于 nRF52840 最终用户设备 1 和笔记本电脑都订阅了 ff05::abcd
,因此 OTBR 可以收到这两次 ping 回复。这表明 OTBR 可以将 IPv6 Ping 请求多播数据包从 Wi-Fi 网络转发到线程网络。
8. 验证出站 IPv6 多播
在 nRF52840 端点设备 2 上 ping ff05::abcd:
$ 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 回复多播软件包从线程网络转发到 Wi-Fi 网络。
9. 恭喜
恭喜!您已成功设置线程边界路由器并验证了双向 IPv6 多播!
如需详细了解 OpenThread,请访问 openthread.io。
参考文档: