Моделирование сети потоков с использованием OpenThread в Docker

1. Введение

26b7f4f6b3ea0700.png

OpenThread , выпущенный Google, представляет собой реализацию сетевого протокола Thread с открытым исходным кодом. Google Nest выпустил OpenThread, чтобы сделать технологию, используемую в продуктах Nest, широко доступной для разработчиков, чтобы ускорить разработку продуктов для подключенного дома.

Спецификация Thread определяет надежный, безопасный и маломощный протокол беспроводной связи между устройствами на основе IPv6 для домашних приложений. OpenThread реализует все сетевые уровни потоков, включая IPv6, 6LoWPAN, IEEE 802.15.4 с безопасностью MAC, установлением Mesh Link и маршрутизацией Mesh.

Этот Codelab проведет вас через моделирование сети Thread на эмулируемых устройствах с помощью Docker.

Что вы узнаете

  • Как настроить цепочку инструментов сборки OpenThread
  • Как смоделировать сеть потоков
  • Как аутентифицировать узлы потока
  • Как управлять сетью потоков с помощью OpenThread Daemon

Что вам понадобится

  • Докер
  • Базовые знания Linux, сетевой маршрутизации

2. Настройте Докер

Этот Codelab предназначен для использования Docker на компьютере с Linux, Mac OS X или Windows. Linux является рекомендуемой средой.

Установить Докер

Установите Docker на выбранную вами ОС.

Извлеките образ Docker

После установки Docker откройте окно терминала и извлеките openthread/environment Docker. В этом образе представлены OpenThread и OpenThread Daemon, предварительно созданные и готовые к использованию в Codelab.

$ 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

Обратите внимание на флаги, которые необходимы для этой лаборатории кода:

  • --sysctl net.ipv6.conf.all.disable_ipv6=0 — включает IPv6 внутри контейнера.
  • --cap-add=net_admin — включает возможность NET_ADMIN, которая позволяет вам выполнять операции, связанные с сетью, такие как добавление IP-маршрутов.

Оказавшись в контейнере, вы должны увидеть подсказку, подобную этой:

root@c0f3912a74ff:/#

В приведенном выше примере c0f3912a74ff — это идентификатор контейнера. Идентификатор контейнера для вашего экземпляра контейнера Docker будет отличаться от идентификатора, показанного в подсказках для этой лаборатории кода.

Использование Докера

В этой Codelab предполагается, что вы знакомы с основами использования Docker. Вы должны оставаться в контейнере Docker на протяжении всей работы Codelab.

3. Смоделируйте сеть потоков

Пример приложения, которое вы будете использовать для этой Codelab, демонстрирует минимальное приложение OpenThread, которое предоставляет интерфейсы конфигурации и управления OpenThread через базовый интерфейс командной строки (CLI).

В этом упражнении вы выполните минимальные шаги, необходимые для эхо-запроса одного эмулированного устройства 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 создайте процесс CLI для эмулируемого устройства Thread, используя двоичный файл ot-cli-ftd .

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 для эмулируемого устройства. Это значение также используется при привязке к порту UDP для эмуляции радиосвязи IEEE 802.15.4 (порт = 9000 + файловый дескриптор). Каждый экземпляр эмулируемого устройства Thread в Codelab будет использовать другой файловый дескриптор.

Примечание. Используйте только файловые дескрипторы 1 или выше, как указано в этой лаборатории кода, при создании процесса для эмулируемого устройства. Дескриптор файла 0 зарезервирован для другого использования.

Создайте новый рабочий набор данных и зафиксируйте его как активный. Операционный набор данных — это конфигурация создаваемой вами сети потоков.

> 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

Подождите несколько секунд и убедитесь, что устройство стало лидером потока. Лидер — это устройство, ответственное за управление назначением идентификатора маршрутизатора.

> state
leader
Done

Просмотрите IPv6-адреса, назначенные интерфейсу Thread узла 1 (вывод будет другим):

> 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 = локальная ссылка

Типы адресов Mesh-local классифицируются далее:

  • Содержит ff:fe00 = локатор маршрутизатора (RLOC)
  • Не содержит ff:fe00 = идентификатор конечной точки (EID)

Определите EID в выводе консоли, запишите его для дальнейшего использования. В приведенном выше примере выходных данных EID:

fd61:2344:9a52:ede0:d041:c5ba:a7bc:5ce6

2. Запустите узел 2

Откройте новый терминал и запустите оболочку bash в запущенном в данный момент контейнере Docker, чтобы использовать его для Node 2.

$ docker exec -it codelab_otsim_ctnr bash

В этом новом приглашении bash запустите процесс CLI с аргументом 2 . Это ваше второе эмулированное устройство Thread:

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

Примечание. Если вы не видите приглашение > после выполнения этой команды, нажмите enter ВВОД.

Настройте сетевой ключ потока и идентификатор PAN, используя те же значения, что и в рабочем наборе данных узла 1:

> dataset networkkey e4344ca17d1dca2a33f064992f31f786
Done
> dataset panid 0xc169
Done

Зафиксируйте этот набор данных как активный:

> dataset commit active
Done

Поднимите интерфейс IPv6:

> ifconfig up
Done

Запустить операцию протокола Thread:

> thread start
Done

Устройство инициализируется как дочернее. Дочерний поток эквивалентен конечному устройству, которое представляет собой устройство потока, которое передает и получает одноадресный трафик только с родительским устройством.

> state
child
Done

В течение 2 минут вы должны увидеть переключение состояния с child на router . Маршрутизатор потоков способен маршрутизировать трафик между устройствами потоков. Его также называют Родителем.

> state
router
Done

Проверьте сеть

Простой способ проверить ячеистую сеть — посмотреть таблицу маршрутизатора.

1. Проверьте подключение

На узле 2 получите RLOC16. RLOC16 — это последние 16 бит IPv6-адреса RLOC устройства.

> rloc16
5800
Done

На узле 1 проверьте таблицу маршрутизаторов на наличие RLOC16 узла 2. Убедитесь, что узел 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 |

RLOC узла 2, равный 0x5800 , найден в таблице, подтверждая, что он подключен к ячеистой сети.

2. Пропингуйте узел 1 с узла 2.

Проверьте подключение между двумя эмулируемыми устройствами Thread. На узле 2 ping EID, назначенный узлу 1:

> 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, протестируйте ячеистую сеть, отключив один узел.

Вернитесь к узлу 1 и остановите поток:

> 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:/#

Возможно, вам придется нажать enter несколько раз, чтобы вернуть приглашение > после команды factoryreset до заводских настроек. Не выходите из контейнера Docker.

Также сброс к заводским настройкам и выход из узла 1:

> factoryreset
>
> exit
root@c0f3912a74ff:/#

См. Справочник по интерфейсу командной строки OpenThread , чтобы изучить все доступные команды интерфейса командной строки.

4. Аутентификация узлов с вводом в эксплуатацию

В предыдущем упражнении вы настроили сеть Thread с двумя смоделированными устройствами и проверили подключение. Однако это позволяет передавать между устройствами только локальный трафик IPv6, не прошедший проверку подлинности. Для маршрутизации глобального IPv6-трафика между ними (и Интернетом через пограничный маршрутизатор потоков) узлы должны быть аутентифицированы.

Для аутентификации одно устройство должно выступать в роли комиссара. Уполномоченный в настоящее время является выбранным сервером аутентификации для новых устройств Thread и авторизатором для предоставления сетевых учетных данных, необходимых для подключения устройств к сети.

В этом упражнении мы будем использовать ту же двухузловую топологию, что и раньше. Для аутентификации лидер потока будет выступать в роли комиссара, а маршрутизатор потока — в качестве присоединителя.

d6a67e8a0d0b5dcb.png

Докер

Для каждого узла (окна терминала) в оставшихся упражнениях убедитесь, что вы используете контейнер Docker со сборкой OpenThread. Если продолжить предыдущее упражнение, у вас все еще должны быть открыты два приглашения bash в одном и том же контейнере Docker. Если нет, см. шаг « Устранение неполадок Docker » или просто повторите упражнение « Симуляция сети потока».

1. Создайте сеть

В узле 1 создайте процесс CLI:

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

Примечание. Если вы не видите приглашение > после выполнения этой команды, нажмите enter ВВОД.

Создайте новый рабочий набор данных, зафиксируйте его как активный и запустите поток:

> 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 комиссию в сеть. Joiner — это устройство, добавляемое администратором-человеком во введенную в действие сеть потоков.

> commissioner joiner add * J01NME
Done

3. Запустите роль Столяра

Во втором окне терминала в контейнере Docker создайте новый процесс CLI. Это узел 2.

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

На узле 2 включите роль присоединителя, используя учетные данные присоединителя J01NME .

> ifconfig up
Done
> joiner start J01NME
Done

... подождите несколько секунд для подтверждения ...

Join success

В качестве присоединителя устройство (узел 2) успешно аутентифицировало себя с помощью уполномоченного (узел 1) и получило учетные данные сети потоков.

Теперь, когда узел 2 аутентифицирован, запустите Thread:

> thread start
Done

4. Подтвердить сетевую аутентификацию

Проверьте state на узле 2, чтобы убедиться, что он присоединился к сети. В течение двух минут Node 2 переходит от child к router :

> state
child
Done
...
> state
router
Done

5. Сбросить настройки

Чтобы подготовиться к следующему упражнению, сбросьте конфигурацию. На каждом узле остановите Thread, выполните сброс до заводских настроек и выйдите из эмулируемого устройства Thread:

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

Возможно, вам придется нажать enter несколько раз, чтобы вернуть приглашение > после команды factoryreset до заводских настроек.

5. Управляйте сетью с помощью OpenThread Daemon

В этом упражнении мы собираемся смоделировать один экземпляр CLI (одно встроенное устройство SoC Thread) и один экземпляр Radio Co-Processor (RCP).

ot-daemon — это режим приложения OpenThread Posix, который использует сокет UNIX в качестве ввода и вывода, чтобы ядро ​​OpenThread могло работать как служба. Клиент может взаимодействовать с этой службой, подключившись к сокету с помощью интерфейса командной строки OpenThread в качестве протокола.

ot-ctl — это интерфейс командной строки, предоставляемый ot-daemon для управления и настройки RCP. Используя это, мы подключим RCP к сети, созданной устройством Thread.

Докер

Для каждого узла (окна терминала) в этом упражнении убедитесь, что вы используете контейнер Docker со сборкой OpenThread. Если вы продолжаете предыдущее упражнение, у вас должно быть уже открыто два приглашения bash в одном и том же контейнере Docker. Если нет, см. шаг « Устранение неполадок Docker ».

Использовать ot-демон

В этом упражнении будут использоваться три окна терминала, соответствующие следующему:

  1. Экземпляр CLI моделируемого устройства Thread (узел 1)
  2. ot-daemon процесс
  3. экземпляр командной строки ot-ctl

1. Запустите узел 1

В первом окне терминала создайте процесс CLI для вашего эмулируемого устройства Thread:

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

Примечание. Если вы не видите приглашение > после выполнения этой команды, нажмите enter ВВОД.

Создайте новый рабочий набор данных, зафиксируйте его как активный и запустите поток:

> 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

Просмотрите IPv6-адреса, назначенные интерфейсу Thread узла 1:

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

Как объяснялось в шаге Simulate a Thread network , один адрес является локальным для канала ( fe80 ), а три — локальным для сетки ( fd ). EID — это локальный адрес сети, который не содержит ff:fe00 в адресе. В этом примере выходных данных EID равен fd55:cf34:dea5:7994:460:872c:e807:c4ab .

Определите конкретный EID из выходных данных ipaddr , который будет использоваться для связи с узлом.

2. Запустите ot-демон

Во втором окне терминала создайте узел устройства tun и установите права на чтение/запись:

root@c0f3912a74ff:/# mkdir -p /dev/net && mknod /dev/net/tun c 10 200
root@c0f3912a74ff:/# chmod 600 /dev/net/tun

Это устройство используется для передачи и приема пакетов в виртуальных устройствах. Вы можете получить сообщение об ошибке, если устройство уже создано — это нормально и его можно игнорировать.

Запустите ot-daemon для узла RCP, который мы назовем узлом 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 для подключения к сети

Мы еще не задействовали Node 2 ( ot-daemon RCP) ни в одной сети Thread. Здесь на помощь приходит ot- ot-ctl . ot-ctl использует тот же интерфейс командной строки, что и приложение 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 в этом третьем окне терминала для управления Node 2 (узел RCP), который вы запустили во втором окне терминала с помощью ot-daemon . Проверьте state узла 2:

> state
disabled
Done

Получите eui64 Node 2, чтобы ограничить присоединение к определенному присоединителю:

> eui64
18b4300000000001
Done

На узле 1 (первое окно терминала) запустите Комиссара и ограничьте присоединение только этим eui64:

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

В третьем окне терминала откройте сетевой интерфейс для Node 2 и подключитесь к сети:

> ifconfig up
Done
> joiner start J01NME
Done

... подождите несколько секунд для подтверждения ...

Join success

Как присоединитель, RCP (узел 2) успешно аутентифицировал себя с уполномоченным (узел 1) и получил учетные данные сети потоков.

Теперь присоедините Node 2 к сети Thread (опять же, в третьем окне терминала):

> thread start
Done

4. Подтвердить сетевую аутентификацию

В третьем терминале проверьте state узла 2, чтобы убедиться, что он присоединился к сети. В течение двух минут Node 2 переходит от child к router :

> state
child
Done
...
> state
router
Done

5. Подтвердить подключение

В третьем окне терминала выйдите из ot-ctl , используя либо Ctrl+D , либо команду exit , и вернитесь в консоль bash контейнера. С этой консоли отправьте эхо-запрос на узел 1, используя его EID с командой ping6 . Если экземпляр RCP ot-daemon успешно присоединен к сети Thread и взаимодействует с ней, проверка связи завершается успешно:

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

bash , вам может потребоваться проверить, работает ли он, и перезапустить / повторно войти по мере необходимости.

Чтобы показать, какие контейнеры 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

Если вы не видите контейнер codelab_otsim_ctnr в выводе какой-либо команды docker ps , запустите ее еще раз:

$ docker run --name codelab_otsim_ctnr -it --rm \
   --sysctl net.ipv6.conf.all.disable_ipv6=0 \
   --cap-add=net_admin openthread/environment bash

Если контейнер остановлен (перечислен в 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 Allowed, убедитесь, что вы используете Docker от имени пользователя root в соответствии с командами, представленными в этой лаборатории кода. Этот Codelab не поддерживает запуск Docker в режиме без рута .

7. Поздравляем!

Вы успешно смоделировали свою первую сеть Thread с помощью OpenThread. Потрясающий!

В этой лаборатории кода вы узнали, как:

  • Запуск контейнера OpenThread Simulation Docker и управление им
  • Смоделируйте сеть потоков
  • Аутентификация узлов потока
  • Управление сетью потоков с помощью OpenThread Daemon

Чтобы узнать больше о Thread и OpenThread, изучите эти ссылки:

Или попробуйте использовать OpenThread Border Router в контейнере Docker !