Lorawan-stack: Confirmar la sesión del dispositivo final según los mensajes del servidor de red

Creado en 8 ene. 2021  ·  8Comentarios  ·  Fuente: TheThingsNetwork/lorawan-stack

Resumen

El servidor de aplicaciones debe confirmar la sesión del dispositivo final (es decir, mover dev.PendingSession a dev.Session ) en los siguientes eventos:

  • Mensaje de enlace ascendente (ya ocurre)
  • Ack de enlace descendente
  • Nack de enlace descendente
  • El enlace descendente falló (si el error no es una sesión desconocida)
  • Cola de enlace descendente invalidada

¿Porqué necesitamos esto?

Actualmente, es posible que el NS 'cambie' la sesión sin que el AS sepa que este cambio ocurrió. @rvolosatovs reprodujo esto en v3.11 usando la siguiente secuencia.

  • El dispositivo final se une: AS conoce esta sesión como dev.PendingSession
  • El dispositivo final envía FPort = 0 uplink - AS no recibirá este uplink
  • El servidor de red programa un enlace descendente FPort = 0
  • Los servidores de red envían un evento DownlinkQueueInvalidated al AS
  • AS rechaza esta invalidación de la cola de enlace descendente ya que no tiene un dev.Session

En este punto, el AS nunca podrá programar enlaces descendentes nuevamente en esta sesión a menos que el NS envíe otra invalidación en el futuro, porque básicamente rechazó el aumento de FCnt que ocurrió cuando el NS envió un FPort = 0 enlace descendente (y ahora el FCnt siempre es demasiado bajo).

¿Qué hay ya ahí? ¿Qué ves ahora?

La sesión no se recuperará a menos que ocurra una invalidación en el futuro.

¿Lo que falta? ¿Qué quieres ver?

  • Agregue SessionKeyID a DownlinkQueueInvalidation . Si la cola está vacía, el AS no puede saber en este momento qué cola fue invalidada.
  • El AS debe actualizar la cola + FCnt de la sesión correcta, en lugar de asumir siempre que la invalidación es aproximadamente dev.Session .
  • El AS debe verificar de qué sesión es un mensaje nacked ; es posible que el mensaje nacked sea ​​de una sesión pendiente (desde la perspectiva del AS) y, como tal, la actualización de FCnt debe realizarse en la sesión correcta.
  • Finalmente, el AS debería cambiar la sesión normal entre dev.PendingSession y dev.Session cuando se produzcan los mensajes mencionados en Summary .

Ambiente

v3.11

¿Cómo se propone implementar esto?

  • Agregue el campo de proto requerido y complételo en el lado NS.
  • Compruebe qué sesión estamos usando durante la invalidación / nack y asegúrese de actualizar esa en el AS.
  • Mueva el procedimiento de cambio de sesión fuera de handleUplink y hágalo en todos los tipos de enlace ascendente apropiados.
  • (Opcional) devuelva los detalles del error en DownlinkQueue{Push|Replace} con el mínimo de FCnt y actualice siempre LastAFCntDown a este valor. Esto aseguraría que el sistema converge si en algún momento no estamos sincronizados entre AS y NS por alguna razón.

¿Cómo propones probar esto?

Intente reproducir la secuencia mencionada en los pasos de reproducción.

¿Puede hacer esto usted mismo y enviar una solicitud de extracción?

Sí, pero como se trata de un cambio no trivial, solicito que se etiquete este problema primero como discussion : ¿queremos introducir estos cambios? La invalidación de la cola de enlace descendente parece un requisito, pero las otras son buenas para la coherencia.

cc @rvolosatovs

bug application server network server in progress

Comentario más útil

He actualizado la prioridad a prio/high ya que está afectando las implementaciones de v3.11.1 .

Los cambios deben ser los siguientes:

  • Agregue SessionKeyID a DownlinkQueueInvalidation . Si la cola está vacía, el AS no puede saber en este momento qué cola fue invalidada.

La siguiente adición proto (campo 3 ) debería ser suficiente.

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];
}
  • El AS debe actualizar la cola + FCnt de la sesión correcta, en lugar de suponer siempre que la invalidación se trata de dev.Session .

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

En lugar de usar dev.Session siempre, cambie SessionKeyID para establecer qué sesión usar. Si es necesario, actualice el dev.Session actual.

  • El AS debe verificar de qué sesión es un mensaje nacked ; es posible que el mensaje nacked sea ​​de una sesión pendiente (desde la perspectiva del AS) y, como tal, la actualización de FCnt debe realizarse en la sesión correcta.

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

Como antes, cambie SessionKeyID para determinar qué sesión usar. Si es necesario, actualice el dev.Session actual.

  • (Opcional) devuelva los detalles del error en DownlinkQueue{Push|Replace} con el mínimo FCnt y siempre actualice LastAFCntDown a este valor. Esto aseguraría que el sistema converge si en algún momento no estamos sincronizados entre AS y NS por alguna razón.

La siguiente adición proto debe completarse y agregarse como detalles de error al errFCntTooLow en el NS:

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

El AS puede tomar estos detalles y actualizar la sesión actual.

Los cambios son compatibles con versiones anteriores y, con suerte, mínimos en el lado NS. El genio ya salió de la botella: todo el protocolo entre AS y NS se volvió asincrónico lentamente, y simplemente revertir el cambio FPort=0 no será suficiente. No creo que esta transformación esté mal al final del día, pero debemos corregir estas peculiaridades con respecto a la bisimulación de la sesión.

cc @johanstokking , @rvolosatovs

Todos 8 comentarios

Estoy a favor de esto, como ya hemos comentado.
El servidor de aplicaciones siempre debe confiar en el servidor de red, porque siempre tiene los datos más actualizados sobre la sesión del dispositivo.

  • El dispositivo final envía FPort = 0 uplink - AS no recibirá este uplink

¿No deberíamos cambiar esto para que NS envíe esto, pero con una carga útil vacía y FPort 0, para que no se envíe en sentido ascendente?

  • El dispositivo final envía FPort = 0 uplink - AS no recibirá este uplink

¿No deberíamos cambiar esto para que NS envíe esto, pero con una carga útil vacía y FPort 0, para que no se envíe en sentido ascendente?

Es redundante, dado que la mensajería NS-> AS es asíncrona, la invalidación de la cola puede llegar antes de que se envíe el enlace ascendente FPort==0 a AS para confirmar la sesión, por lo que tenemos que hacer esto de todos modos. La única razón para enviar un enlace ascendente a AS en respuesta a FPort==0 enlace ascendente a NS, sería garantizar que AS sea notificado del cambio de sesión lo antes posible, pero no tenemos esa necesidad. Incluso entonces, tendría mucho más sentido introducir un mensaje SessionSwitch , que NS enviaría a AS en lugar del enlace ascendente FPort 0.

He actualizado la prioridad a prio/high ya que está afectando las implementaciones de v3.11.1 .

Los cambios deben ser los siguientes:

  • Agregue SessionKeyID a DownlinkQueueInvalidation . Si la cola está vacía, el AS no puede saber en este momento qué cola fue invalidada.

La siguiente adición proto (campo 3 ) debería ser suficiente.

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];
}
  • El AS debe actualizar la cola + FCnt de la sesión correcta, en lugar de suponer siempre que la invalidación se trata de dev.Session .

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

En lugar de usar dev.Session siempre, cambie SessionKeyID para establecer qué sesión usar. Si es necesario, actualice el dev.Session actual.

  • El AS debe verificar de qué sesión es un mensaje nacked ; es posible que el mensaje nacked sea ​​de una sesión pendiente (desde la perspectiva del AS) y, como tal, la actualización de FCnt debe realizarse en la sesión correcta.

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

Como antes, cambie SessionKeyID para determinar qué sesión usar. Si es necesario, actualice el dev.Session actual.

  • (Opcional) devuelva los detalles del error en DownlinkQueue{Push|Replace} con el mínimo FCnt y siempre actualice LastAFCntDown a este valor. Esto aseguraría que el sistema converge si en algún momento no estamos sincronizados entre AS y NS por alguna razón.

La siguiente adición proto debe completarse y agregarse como detalles de error al errFCntTooLow en el NS:

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

El AS puede tomar estos detalles y actualizar la sesión actual.

Los cambios son compatibles con versiones anteriores y, con suerte, mínimos en el lado NS. El genio ya salió de la botella: todo el protocolo entre AS y NS se volvió asincrónico lentamente, y simplemente revertir el cambio FPort=0 no será suficiente. No creo que esta transformación esté mal al final del día, pero debemos corregir estas peculiaridades con respecto a la bisimulación de la sesión.

cc @johanstokking , @rvolosatovs

¡Suena bien para mí!

¿Algo que pueda hacer aquí? Si es así, vuelva a asignarme y déjeme saber qué.

¿Algo que pueda hacer aquí? Si es así, vuelva a asignarme y déjeme saber qué.

Ya estoy trabajando en esto, con un gran énfasis en el siguiente punto:

* (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.

La razón de esto es que tomar acciones basadas en los eventos recibidos de la NS, como parte de la cola, no es fundamentalmente suficiente:

  • Los mensajes pueden ser antiguos, pero queremos hacer arreglos en la cola _ahora_
  • Los mensajes se pueden perder: la cola no es infinita
  • Los mensajes se pueden reordenar: se insertan de forma asincrónica en la cola y se muestran de manera potencialmente reordenada.

Dadas estas características, existen dos opciones:

  • Retrase el cálculo de la cola hasta el final del procesamiento por lotes (básicamente, si recibe 10 invalidaciones de cola de enlace descendente, recalcula la cola solo al final). Esto no es suficiente por las siguientes razones:

    • Cuando el AS procesa un lote de mensajes, todavía no sabe si está _ realmente_ al final de la cola o si está procesando algún lote en el medio.

    • Los mensajes aún pueden perderse y determinar su orden no es trivial.

  • Solo confíe en el NS. Lo que quiero decir con esto es que las operaciones de empujar / reemplazar devuelven dev.Session.SessionKeyID , dev.PendingSession.SessionKeyID y LastAFCntDown , como parte de los detalles del error. Luego usamos los detalles del error para reconstruir la sesión en el AS. Básicamente, esto significa que cuando intentamos hacer una operación de cola de enlace descendente, utilizando datos desactualizados (quizás una sesión desactualizada, quizás un FCnt demasiado bajo), eventualmente convergemos al estado NS. Puede tomar uno, dos, tres intentos, lo haré acotado para evitar un giro infinito, pero al menos estamos operando con información que es significativamente más nueva que la de la cola de mensajes de enlace ascendente.
  • Solo confíe en el NS. Lo que quiero decir con esto es que las operaciones de empujar / reemplazar devuelven dev.Session.SessionKeyID , dev.PendingSession.SessionKeyID y LastAFCntDown , como parte de los detalles del error. Luego usamos los detalles del error para reconstruir la sesión en el AS. Básicamente, esto significa que cuando intentamos hacer una operación de cola de enlace descendente, utilizando datos desactualizados (quizás una sesión desactualizada, quizás un FCnt demasiado bajo), eventualmente convergemos al estado NS. Puede tomar uno, dos, tres intentos, lo haré acotado para evitar un giro infinito, pero al menos estamos operando con información que es significativamente más nueva que la de la cola de mensajes de enlace ascendente.

Creo que esta es la mejor opción.

¿Fue útil esta página
0 / 5 - 0 calificaciones

Temas relacionados

johanstokking picture johanstokking  ·  8Comentarios

kschiffer picture kschiffer  ·  4Comentarios

rvolosatovs picture rvolosatovs  ·  9Comentarios

johanstokking picture johanstokking  ·  8Comentarios

thinkOfaNumber picture thinkOfaNumber  ·  4Comentarios