Lorawan-stack: Confirmer la session de l'appareil final en fonction des messages du serveur réseau

Créé le 8 janv. 2021  ·  8Commentaires  ·  Source: TheThingsNetwork/lorawan-stack

Résumé

Le serveur d'applications doit confirmer la session de l'appareil final (c'est-à-dire déplacer dev.PendingSession dans dev.Session ) sur les événements suivants :

  • Message de liaison montante (se produit déjà)
  • Accusé de réception de la liaison descendante
  • Lien descendant
  • Échec de la liaison descendante (si l'erreur n'est pas une session inconnue)
  • File d'attente de liaison descendante invalidée

Pourquoi avons nous besoin de ça?

Actuellement, il est possible que le NS « bascule » la session sans que l'AS sache que ce basculement s'est produit. @rvolosatovs a reproduit cela dans v3.11 utilisant la séquence suivante.

  • Le périphérique final se joint - AS connaît cette session sous le nom de dev.PendingSession
  • Le périphérique final envoie la liaison montante FPort=0 - AS ne recevra pas cette liaison montante
  • Le serveur réseau planifie une liaison descendante FPort=0
  • Les serveurs réseau envoient un événement DownlinkQueueInvalidated à l'AS
  • AS rejette cette invalidation de file d'attente de liaison descendante car il n'a pas de dev.Session

À ce stade, l'AS ne pourra plus jamais planifier de liaisons descendantes dans cette session à moins que le NS n'envoie une autre invalidation dans le futur, car il a essentiellement rejeté l' FCnt qui s'est produite lorsque le NS a envoyé un FPort=0 liaison descendante (et maintenant le FCnt est toujours trop bas).

Qu'est-ce qu'il y a déjà ? Que voyez-vous maintenant?

La session ne sera pas récupérée à moins qu'une invalidation ne se produise à l'avenir.

Que manque-t-il? Qu'est-ce que tu veux voir?

  • Ajoutez SessionKeyID à DownlinkQueueInvalidation . Si la file d'attente est vide, l'AS ne peut pas savoir à ce moment quelle file d'attente a été invalidée.
  • L'AS doit mettre à jour la file d'attente + FCnt de la session correcte, au lieu de toujours supposer que l'invalidation concerne le dev.Session .
  • L'AS doit vérifier de quelle session provient un message nacked - il est possible que le message nacked provienne d'une session en attente (du point de vue de l'AS) et en tant que tel, la mise à jour FCnt doit être effectuée le la bonne séance.
  • Enfin, l'AS doit basculer la session as should entre dev.PendingSession et dev.Session lorsque les messages mentionnés dans Summary se produisent.

Environnement

v3.11

Comment proposez-vous de mettre cela en œuvre ?

  • Ajoutez le champ proto requis et remplissez-le du côté NS.
  • Vérifiez quelle session nous utilisons pendant l'invalidation/nack et assurez-vous de mettre à jour celle-ci dans l'AS.
  • Déplacez la procédure de commutation de session hors de handleUplink et effectuez-la sur tous les types de liaison montante appropriés.
  • (Facultatif) renvoyez les détails de l'erreur sur DownlinkQueue{Push|Replace} avec le minimum FCnt et mettez toujours à jour le LastAFCntDown avec cette valeur. Cela garantirait que le système converge si, pour une raison quelconque, nous sommes désynchronisés entre AS et NS.

Comment proposez-vous de tester cela ?

Essayez de reproduire la séquence mentionnée dans les étapes de reproduction.

Pouvez-vous le faire vous-même et soumettre une Pull Request ?

Oui, mais comme il s'agit d'un changement non trivial, je demande de marquer d'abord ce problème comme discussion - voulons-nous introduire ces changements ? L'invalidation de file d'attente de liaison descendante semble une exigence, mais les autres sont bonnes pour la cohérence.

cc @rvolosatovs

bug application server network server in progress

Commentaire le plus utile

J'ai mis à niveau la priorité à prio/high car cela affecte les déploiements de v3.11.1 .

Les changements devraient être les suivants :

  • Ajoutez SessionKeyID à DownlinkQueueInvalidation . Si la file d'attente est vide, l'AS ne peut pas savoir à ce moment quelle file d'attente a été invalidée.

L'addition suivante de proto (champ 3 ) devrait suffire.

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];
}
  • L'AS doit mettre à jour la file d'attente + FCnt de la session correcte, au lieu de toujours supposer que l'invalidation concerne le dev.Session .

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

Au lieu d'utiliser toujours le dev.Session , faites un basculement sur SessionKeyID afin d'établir quelle session utiliser. Si nécessaire, mettez à jour le dev.Session actuel.

  • L'AS doit vérifier de quelle session provient un message nacked - il est possible que le message nacked provienne d'une session en attente (du point de vue de l'AS) et en tant que tel, la mise à jour FCnt doit être effectuée le la bonne séance.

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

Comme précédemment, faites un switch sur le SessionKeyID afin de déterminer quelle session utiliser. Si nécessaire, mettez à jour le dev.Session actuel.

  • (Facultatif) retournez les détails de l'erreur sur DownlinkQueue{Push|Replace} avec le minimum FCnt et mettez toujours à jour le LastAFCntDown avec cette valeur. Cela garantirait que le système converge si, pour une raison quelconque, nous sommes désynchronisés entre AS et NS.

L'ajout suivant de proto doit être rempli et ajouté en tant que détails d'erreur au errFCntTooLow dans la NS :

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

L'AS peut alors prendre ces détails et mettre à jour la session en cours.

Les modifications sont rétrocompatibles et, espérons-le, minimes du côté NS. Le génie est déjà sorti de la bouteille - l'ensemble du protocole entre AS et NS est lentement devenu asynchrone, et simplement annuler le changement FPort=0 ne suffira pas. Je ne pense pas que cette transformation était erronée en fin de compte, mais nous devons corriger ces bizarreries concernant la bisimulation de session.

cc @johanstokking , @rvolosatovs

Tous les 8 commentaires

Je suis en faveur de cela, comme nous en avons déjà discuté.
Le serveur d'applications doit toujours faire confiance à Network Server, car il dispose toujours des données les plus récentes sur la session du périphérique.

  • Le périphérique final envoie la liaison montante FPort=0 - AS ne recevra pas cette liaison montante

Ne devrions-nous pas changer cela pour que NS envoie cela, mais avec une charge utile vide et FPort 0, afin qu'il ne soit pas envoyé en amont ?

  • Le périphérique final envoie la liaison montante FPort=0 - AS ne recevra pas cette liaison montante

Ne devrions-nous pas changer cela pour que NS envoie cela, mais avec une charge utile vide et FPort 0, afin qu'il ne soit pas envoyé en amont ?

C'est redondant, puisque la messagerie NS->AS est asynchrone, l'invalidation de la file d'attente peut arriver avant que la liaison montante FPort==0 soit envoyée à AS pour confirmer la session, nous devons donc le faire de toute façon. La seule raison d'envoyer une liaison montante à AS en réponse à une liaison montante FPort==0 vers NS serait de s'assurer que AS est informé du changement de session dès que possible, mais nous n'en avons pas besoin. Même dans ce cas, il serait beaucoup plus logique d'introduire un message SessionSwitch , que NS enverrait à AS au lieu de la liaison montante FPort 0.

J'ai mis à niveau la priorité à prio/high car cela affecte les déploiements de v3.11.1 .

Les changements devraient être les suivants :

  • Ajoutez SessionKeyID à DownlinkQueueInvalidation . Si la file d'attente est vide, l'AS ne peut pas savoir à ce moment quelle file d'attente a été invalidée.

L'addition suivante de proto (champ 3 ) devrait suffire.

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];
}
  • L'AS doit mettre à jour la file d'attente + FCnt de la session correcte, au lieu de toujours supposer que l'invalidation concerne le dev.Session .

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

Au lieu d'utiliser toujours le dev.Session , faites un basculement sur SessionKeyID afin d'établir quelle session utiliser. Si nécessaire, mettez à jour le dev.Session actuel.

  • L'AS doit vérifier de quelle session provient un message nacked - il est possible que le message nacked provienne d'une session en attente (du point de vue de l'AS) et en tant que tel, la mise à jour FCnt doit être effectuée le la bonne séance.

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

Comme précédemment, faites un switch sur le SessionKeyID afin de déterminer quelle session utiliser. Si nécessaire, mettez à jour le dev.Session actuel.

  • (Facultatif) retournez les détails de l'erreur sur DownlinkQueue{Push|Replace} avec le minimum FCnt et mettez toujours à jour le LastAFCntDown avec cette valeur. Cela garantirait que le système converge si, pour une raison quelconque, nous sommes désynchronisés entre AS et NS.

L'ajout suivant de proto doit être rempli et ajouté en tant que détails d'erreur au errFCntTooLow dans la NS :

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

L'AS peut alors prendre ces détails et mettre à jour la session en cours.

Les modifications sont rétrocompatibles et, espérons-le, minimes du côté NS. Le génie est déjà sorti de la bouteille - l'ensemble du protocole entre AS et NS est lentement devenu asynchrone, et simplement annuler le changement FPort=0 ne suffira pas. Je ne pense pas que cette transformation était erronée en fin de compte, mais nous devons corriger ces bizarreries concernant la bisimulation de session.

cc @johanstokking , @rvolosatovs

Cela me semble bon !

Tout ce que je peux faire ici ? Si c'est le cas, veuillez me réaffecter et dites-moi quoi.

Tout ce que je peux faire ici ? Si c'est le cas, veuillez me réaffecter et dites-moi quoi.

Je travaille déjà là-dessus, avec un gros accent sur le point suivant :

* (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 raison en est que prendre des mesures basées sur les événements reçus du NS, dans le cadre de la file d'attente, n'est fondamentalement pas vraiment suffisant :

  • Les messages peuvent être anciens, mais nous voulons apporter des correctifs à la file d'attente _maintenant_
  • Les messages peuvent être perdus - la file d'attente n'est pas infinie
  • Les messages peuvent être réorganisés - ils sont poussés de manière asynchrone dans la file d'attente et ils sont affichés de manière potentiellement réorganisée

Compte tenu de ces caractéristiques, deux options s'offrent à vous :

  • Retardez le calcul de la file d'attente à la fin du traitement par lots (en gros si vous recevez 10 invalidations de file d'attente de liaison descendante, vous ne recalculez la file d'attente qu'à la fin). Cela ne suffit pas pour les raisons suivantes :

    • Lorsque l'AS traite un lot de messages, il ne sait toujours pas s'il est _vraiment_ à la fin de la file d'attente, ou s'il traite un lot au milieu

    • Les messages peuvent toujours être perdus, et déterminer leur ordre n'est pas anodin.

  • Juste _faites confiance au NS_. Ce que je veux dire par là, c'est que les opérations push/replace renvoient le dev.Session.SessionKeyID , dev.PendingSession.SessionKeyID et le LastAFCntDown , dans le cadre des détails de l'erreur. Nous utilisons ensuite les détails de l'erreur pour reconstruire la session dans l'AS. Fondamentalement, cela signifie que lorsque nous essayons de faire une opération de file d'attente de liaison descendante, en utilisant des données obsolètes (peut-être une session obsolète, peut-être un FCnt trop bas), nous convergeons finalement vers l'état NS. Cela peut prendre un, deux, trois essais, je vais le limiter afin d'éviter de tourner à l'infini, mais nous fonctionnons au moins avec des informations nettement plus récentes que celles de la file d'attente des messages de liaison montante.
  • Juste _faites confiance au NS_. Ce que je veux dire par là, c'est que les opérations push/replace renvoient le dev.Session.SessionKeyID , dev.PendingSession.SessionKeyID et le LastAFCntDown , dans le cadre des détails de l'erreur. Nous utilisons ensuite les détails de l'erreur pour reconstruire la session dans l'AS. Fondamentalement, cela signifie que lorsque nous essayons de faire une opération de file d'attente de liaison descendante, en utilisant des données obsolètes (peut-être une session obsolète, peut-être un FCnt trop bas), nous convergeons finalement vers l'état NS. Cela peut prendre un, deux, trois essais, je vais le limiter afin d'éviter de tourner à l'infini, mais nous fonctionnons au moins avec des informations nettement plus récentes que celles de la file d'attente des messages de liaison montante.

Je pense que c'est la meilleure option.

Cette page vous a été utile?
0 / 5 - 0 notes

Questions connexes

johanstokking picture johanstokking  ·  5Commentaires

adriansmares picture adriansmares  ·  9Commentaires

w4tsn picture w4tsn  ·  6Commentaires

bafonins picture bafonins  ·  5Commentaires

johanstokking picture johanstokking  ·  3Commentaires