Lorawan-stack: Подтверждение сеанса конечного устройства на основе сообщений сетевого сервера

Созданный на 8 янв. 2021  ·  8Комментарии  ·  Источник: TheThingsNetwork/lorawan-stack

Резюме

Сервер приложений должен подтвердить сеанс конечного устройства (т.е. переместить dev.PendingSession в dev.Session ) при следующих событиях:

  • Сообщение восходящей ссылки (уже происходит)
  • Подтверждение нисходящего канала
  • Нисходящий канал
  • Ошибка нисходящего канала (если ошибка не в неизвестном сеансе)
  • Очередь нисходящего канала признана недействительной

Почему нам это надо?

В настоящее время возможно, что NS «переключает» сеанс, а AS не знает, что это переключение произошло. @rvolosatovs воспроизвел это в v3.11 используя следующую последовательность.

  • Конечное устройство подключается - AS знает об этом сеансе как dev.PendingSession
  • Конечное устройство отправляет FPort = 0 восходящий канал - AS не получит этот восходящий канал
  • Сетевой сервер планирует нисходящий канал FPort = 0
  • Сетевые серверы отправляют в AS событие DownlinkQueueInvalidated
  • AS отклоняет эту недействительность очереди нисходящего канала, поскольку в ней нет dev.Session

На этом этапе AS никогда не сможет снова запланировать нисходящие каналы в этом сеансе, если NS не отправит другое объявление недействительности когда-нибудь в будущем, потому что он в основном отклонил увеличение FCnt которое произошло, когда NS отправил FPort = 0 нисходящий канал (и теперь FCnt всегда слишком низкий).

Что там уже есть? Что ты видишь сейчас?

Сеанс не будет восстановлен, если в будущем не произойдет аннулирование.

Что отсутствует? Что бы вы хотели увидеть?

  • Добавьте SessionKeyID к DownlinkQueueInvalidation . Если очередь пуста, AS не может в данный момент узнать, какая очередь была признана недействительной.
  • AS должна обновлять очередь + FCnt правильного сеанса вместо того, чтобы всегда предполагать, что аннулирование связано с dev.Session .
  • AS должна проверить, из какого сеанса отправлено сообщение nacked - возможно, что сообщение nacked получено из ожидающего сеанса (с точки зрения AS), и поэтому обновление FCnt должно быть выполнено на правильный сеанс.
  • Наконец, AS должна переключить сеанс как следует между dev.PendingSession и dev.Session при появлении сообщений, упомянутых в Summary .

Среда

v3.11

Как вы предлагаете это реализовать?

  • Добавьте необходимое поле proto и заполните его на стороне NS.
  • Проверьте, какой сеанс мы используем во время аннулирования / nack, и обязательно обновите его в AS.
  • Переместите процедуру переключения сеанса из handleUplink и сделайте это для всех подходящих типов восходящих каналов.
  • (Необязательно) возвращать сведения об ошибке для DownlinkQueue{Push|Replace} с минимальным значением FCnt и всегда обновлять LastAFCntDown до этого значения. Это обеспечит сходимость системы, если в какой-то момент мы по какой-то причине рассинхронизируем AS и NS.

Как вы предлагаете это проверить?

Попробуйте воспроизвести последовательность, указанную в шагах воспроизведения.

Можете ли вы сделать это самостоятельно и отправить запрос на слияние?

Да, но поскольку это нетривиальное изменение, я прошу сначала пометить эту проблему как discussion - хотим ли мы внести эти изменения? Обнуление очереди нисходящей линии связи кажется обязательным, но другие хороши для согласованности.

cc @rvolosatovs

bug application server network server in progress

Самый полезный комментарий

Я повысил приоритет до prio/high как он влияет v3.11.1 развертывания

Изменения должны быть следующими:

  • Добавьте SessionKeyID к DownlinkQueueInvalidation . Если очередь пуста, AS не может в данный момент узнать, какая очередь была признана недействительной.

Следующего добавления proto (поле 3 ) должно хватить.

message ApplicationInvalidatedDownlinks {
  repeated ApplicationDownlink downlinks = 1;
  uint32 last_f_cnt_down = 2;
  bytes session_key_id = 3 [(gogoproto.customname) = "SessionKeyID", (validate.rules).bytes.max_len = 2048];
}
  • AS должна обновлять очередь + FCnt правильного сеанса, вместо того, чтобы всегда предполагать, что аннулирование связано с dev.Session .

https://github.com/TheThingsNetwork/lorawan-stack/blob/e2fa6c085eaaf1a0b70939020244875bd01e5857/pkg/applicationserver/applicationserver.go#L1020 -L1038

Вместо того, чтобы всегда использовать dev.Session , включите SessionKeyID , чтобы определить, какой сеанс использовать. При необходимости обновите текущий dev.Session .

  • AS должна проверить, из какого сеанса отправлено сообщение nacked - возможно, что сообщение nacked получено из ожидающего сеанса (с точки зрения AS), и поэтому обновление FCnt должно быть выполнено на правильный сеанс.

https://github.com/TheThingsNetwork/lorawan-stack/blob/e2fa6c085eaaf1a0b70939020244875bd01e5857/pkg/applicationserver/applicationserver.go#L1060 -L1073

Как и раньше, включите SessionKeyID , чтобы определить, какой сеанс использовать. При необходимости обновите текущий dev.Session .

  • (Необязательно) возвращать сведения об ошибке для DownlinkQueue{Push|Replace} с минимальным значением FCnt и всегда обновлять LastAFCntDown до этого значения. Это обеспечит сходимость системы, если в какой-то момент мы по какой-то причине рассинхронизируем AS и NS.

Следующее дополнение proto должно быть заполнено и добавлено в качестве сведений об ошибке к errFCntTooLow в NS:

message UpdateDownlinkQueueErrorDetails {
  bytes session_key_id = 1 [(gogoproto.customname) = "SessionKeyID", (validate.rules).bytes.max_len = 2048];
  uint32 last_f_cnt_down = 2;
}

Затем AS может использовать эти данные и обновить текущий сеанс.

Изменения обратно совместимы и, надеюсь, минимальны на стороне NS. Джин уже вышел из бутылки - весь протокол между AS и NS постепенно стал асинхронным, и простого возврата изменения FPort=0 будет недостаточно. Я не думаю, что это преобразование было неправильным в конце концов, но мы должны исправить эти причуды, касающиеся бисимуляции сеанса.

cc @johanstokking , @rvolosatovs

Все 8 Комментарий

Я за это, о чем мы уже говорили.
Сервер приложений всегда должен доверять сетевому серверу, потому что он всегда имеет самые свежие данные о сеансе устройства.

  • Конечное устройство отправляет FPort = 0 восходящий канал - AS не получит этот восходящий канал

Разве мы не должны изменить это так, чтобы NS отправлял это, но с пустой полезной нагрузкой и FPort 0, чтобы он не отправлялся в восходящем направлении?

  • Конечное устройство отправляет FPort = 0 восходящий канал - AS не получит этот восходящий канал

Разве мы не должны изменить это так, чтобы NS отправлял это, но с пустой полезной нагрузкой и FPort 0, чтобы он не отправлялся в восходящем направлении?

Это избыточно, поскольку обмен сообщениями NS-> AS является асинхронным, аннулирование очереди может произойти до того, как восходящий канал FPort==0 будет отправлен в AS для подтверждения сеанса, поэтому мы должны сделать это в любом случае. Единственная причина для отправки восходящего канала на AS в ответ на восходящий канал FPort==0 на NS - это обеспечить уведомление AS об изменении сеанса как можно скорее, но у нас нет такой необходимости. Даже тогда было бы разумнее ввести сообщение SessionSwitch , которое NS будет отправлять в AS вместо восходящего канала FPort 0.

Я повысил приоритет до prio/high как он влияет v3.11.1 развертывания

Изменения должны быть следующими:

  • Добавьте SessionKeyID к DownlinkQueueInvalidation . Если очередь пуста, AS не может в данный момент узнать, какая очередь была признана недействительной.

Следующего добавления proto (поле 3 ) должно хватить.

message ApplicationInvalidatedDownlinks {
  repeated ApplicationDownlink downlinks = 1;
  uint32 last_f_cnt_down = 2;
  bytes session_key_id = 3 [(gogoproto.customname) = "SessionKeyID", (validate.rules).bytes.max_len = 2048];
}
  • AS должна обновлять очередь + FCnt правильного сеанса, вместо того, чтобы всегда предполагать, что аннулирование связано с dev.Session .

https://github.com/TheThingsNetwork/lorawan-stack/blob/e2fa6c085eaaf1a0b70939020244875bd01e5857/pkg/applicationserver/applicationserver.go#L1020 -L1038

Вместо того, чтобы всегда использовать dev.Session , включите SessionKeyID , чтобы определить, какой сеанс использовать. При необходимости обновите текущий dev.Session .

  • AS должна проверить, из какого сеанса отправлено сообщение nacked - возможно, что сообщение nacked получено из ожидающего сеанса (с точки зрения AS), и поэтому обновление FCnt должно быть выполнено на правильный сеанс.

https://github.com/TheThingsNetwork/lorawan-stack/blob/e2fa6c085eaaf1a0b70939020244875bd01e5857/pkg/applicationserver/applicationserver.go#L1060 -L1073

Как и раньше, включите SessionKeyID , чтобы определить, какой сеанс использовать. При необходимости обновите текущий dev.Session .

  • (Необязательно) возвращать сведения об ошибке для DownlinkQueue{Push|Replace} с минимальным значением FCnt и всегда обновлять LastAFCntDown до этого значения. Это обеспечит сходимость системы, если в какой-то момент мы по какой-то причине рассинхронизируем AS и NS.

Следующее дополнение proto должно быть заполнено и добавлено в качестве сведений об ошибке к errFCntTooLow в NS:

message UpdateDownlinkQueueErrorDetails {
  bytes session_key_id = 1 [(gogoproto.customname) = "SessionKeyID", (validate.rules).bytes.max_len = 2048];
  uint32 last_f_cnt_down = 2;
}

Затем AS может использовать эти данные и обновить текущий сеанс.

Изменения обратно совместимы и, надеюсь, минимальны на стороне NS. Джин уже вышел из бутылки - весь протокол между AS и NS постепенно стал асинхронным, и простого возврата изменения FPort=0 будет недостаточно. Я не думаю, что это преобразование было неправильным в конце концов, но мы должны исправить эти причуды, касающиеся бисимуляции сеанса.

cc @johanstokking , @rvolosatovs

Звучит неплохо!

Что я могу здесь сделать? Если да, пожалуйста, назначьте меня заново и дайте мне знать, что именно.

Что я могу здесь сделать? Если да, пожалуйста, назначьте меня заново и дайте мне знать, что именно.

Я уже работаю над этим, уделяя особое внимание следующему:

* (Optional) return error details on `DownlinkQueue{Push|Replace}` with the minimum `FCnt` and always update the `LastAFCntDown` to this value. This would ensure that the system converges if at any point we're for some reason out of sync between AS and NS.

Причина этого в том, что выполнения действий на основе событий, полученных от NS, как части очереди, в принципе недостаточно:

  • Сообщения могут быть старыми, но мы хотим исправить очередь _сейчас_
  • Сообщения могут быть потеряны - очередь не бесконечна
  • Сообщения могут быть переупорядочены - они асинхронно помещаются в очередь и выталкиваются потенциально переупорядоченными способами.

Учитывая эти характеристики, есть два варианта:

  • Отложите вычисление очереди до конца пакетной обработки (в основном, если вы получаете 10 аннулирований очереди нисходящего канала, вы пересчитываете очередь только в конце). Этого недостаточно по следующим причинам:

    • Когда AS обрабатывает пакет сообщений, он все еще не знает, действительно ли он находится в конце очереди или обрабатывает какой-то пакет в середине.

    • Сообщения по-прежнему могут быть потеряны, и определить их порядок нетривиально.

  • Просто доверяйте NS_. Я имею в виду, что операции вставки / замены возвращают dev.Session.SessionKeyID , dev.PendingSession.SessionKeyID и LastAFCntDown как часть сведений об ошибке. Затем мы используем сведения об ошибке для восстановления сеанса в AS. По сути, это означает, что, когда мы пытаемся выполнить операцию очереди нисходящего канала, используя устаревшие данные (возможно, устаревший сеанс, возможно, слишком низкий FCnt), мы в конечном итоге переходим к состоянию NS. Это может занять одну, две, три попытки, я сделаю это ограниченным, чтобы избежать бесконечного вращения, но мы, по крайней мере, работаем с информацией, которая значительно новее, чем информация из очереди сообщений восходящего канала.
  • Просто доверяйте NS_. Я имею в виду, что операции вставки / замены возвращают dev.Session.SessionKeyID , dev.PendingSession.SessionKeyID и LastAFCntDown как часть сведений об ошибке. Затем мы используем сведения об ошибке для восстановления сеанса в AS. По сути, это означает, что, когда мы пытаемся выполнить операцию очереди нисходящего канала, используя устаревшие данные (возможно, устаревший сеанс, возможно, слишком низкий FCnt), мы в конечном итоге переходим к состоянию NS. Это может занять одну, две, три попытки, я сделаю это ограниченным, чтобы избежать бесконечного вращения, но мы, по крайней мере, работаем с информацией, которая значительно новее, чем информация из очереди сообщений восходящего канала.

Думаю, это лучший вариант.

Была ли эта страница полезной?
0 / 5 - 0 рейтинги