Lorawan-stack: Confirme a sessão do dispositivo final com base nas mensagens do servidor de rede

Criado em 8 jan. 2021  ·  8Comentários  ·  Fonte: TheThingsNetwork/lorawan-stack

Resumo

O servidor de aplicativos deve confirmar a sessão do dispositivo final (ou seja, mover dev.PendingSession para dev.Session ) nos seguintes eventos:

  • Mensagem de uplink (já acontece)
  • Downlink ack
  • Downlink nack
  • Falha no downlink (se o erro não for de sessão desconhecida)
  • Fila de downlink invalidada

Por que nós precisamos disso?

Atualmente, é possível que o NS 'troque' a sessão sem que o AS saiba que essa troca ocorreu. @rvolosatovs reproduziu isso em v3.11 usando a seguinte seqüência.

  • Entradas no dispositivo final - AS conhece esta sessão como dev.PendingSession
  • Dispositivo final envia FPort = 0 uplink - AS não receberá este uplink
  • O Network Server agenda um downlink FPort = 0
  • Os servidores de rede enviam um evento DownlinkQueueInvalidated para o AS
  • AS rejeita esta invalidação de fila de downlink, pois não tem um dev.Session

Neste ponto, o AS nunca será capaz de agendar downlinks novamente nesta sessão, a menos que o NS envie outra invalidação em algum momento no futuro, porque basicamente rejeitou o aumento de FCnt que aconteceu quando o NS enviou um FPort = 0 downlink (e agora o FCnt é sempre muito baixo).

O que já está aí? O que você vê agora?

A sessão não se recuperará, a menos que ocorra uma invalidação no futuro.

O que está faltando? O que você quer ver?

  • Adicione SessionKeyID a DownlinkQueueInvalidation . Se a fila estiver vazia, o AS não pode saber neste momento qual fila foi invalidada.
  • O AS deve atualizar a fila + FCnt da sessão correta, ao invés de sempre assumir que a invalidação é sobre dev.Session .
  • O AS deve verificar de qual sessão uma mensagem nacked é - é possível que a mensagem nacked seja de uma sessão pendente (da perspectiva do AS) e, como tal, a atualização do FCnt deve ser feita em a sessão correta.
  • Finalmente, o AS deve alternar a sessão como deveria entre dev.PendingSession e dev.Session quando as mensagens mencionadas em Summary ocorrerem.

Meio Ambiente

v3.11

Como você pretende implementar isso?

  • Adicione o campo protótipo obrigatório e preencha-o no lado NS.
  • Verifique qual sessão estamos usando durante a invalidação / nack e certifique-se de atualizar essa no AS.
  • Mova o procedimento de troca de sessão de handleUplink e faça-o em todos os tipos de uplink apropriados.
  • (Opcional) retorne detalhes do erro em DownlinkQueue{Push|Replace} com o mínimo de FCnt e sempre atualize LastAFCntDown para este valor. Isso garantiria a convergência do sistema se, em algum ponto, ficarmos, por algum motivo, fora de sincronia entre AS e NS.

Como você pretende testar isso?

Tente reproduzir a seqüência mencionada nas etapas de reprodução.

Você pode fazer isso sozinho e enviar uma solicitação pull?

Sim, mas como esta é uma alteração não trivial, estou perguntando, primeiro, marcando esse problema como discussion - queremos introduzir essas alterações? A invalidação da fila de downlink uma parece um requisito, mas as outras são boas para consistência.

cc @rvolosatovs

bug application server network server in progress

Comentários muito úteis

Eu atualizei a prioridade para prio/high pois ela está afetando v3.11.1 implantações.

As mudanças devem ser as seguintes:

  • Adicione SessionKeyID a DownlinkQueueInvalidation . Se a fila estiver vazia, o AS não pode saber neste momento qual fila foi invalidada.

A seguinte proto adição (campo 3 ) deve 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];
}
  • O AS deve atualizar a fila + FCnt da sessão correta, ao invés de sempre assumir que a invalidação é sobre dev.Session .

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

Em vez de usar dev.Session sempre, mude SessionKeyID para estabelecer qual sessão usar. Se necessário, atualize o dev.Session atual.

  • O AS deve verificar de qual sessão uma mensagem nacked é - é possível que a mensagem nacked seja de uma sessão pendente (da perspectiva do AS) e, como tal, a atualização do FCnt deve ser feita em a sessão correta.

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

Como antes, mude o SessionKeyID para determinar qual sessão usar. Se necessário, atualize o dev.Session atual.

  • (Opcional) retorne detalhes do erro em DownlinkQueue{Push|Replace} com o mínimo de FCnt e sempre atualize LastAFCntDown para este valor. Isso garantiria a convergência do sistema se, em algum ponto, ficarmos, por algum motivo, fora de sincronia entre AS e NS.

A seguinte adição proto deve ser preenchida e adicionada como detalhes do erro a errFCntTooLow no NS:

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

O AS pode então pegar esses detalhes e atualizar a sessão atual.

As alterações são compatíveis com versões anteriores e, esperançosamente, mínimas no lado do NS. O gênio já saiu da garrafa - todo o protocolo entre AS e NS lentamente se tornou assíncrono e simplesmente reverter a mudança FPort=0 não será suficiente. Não acho que essa transformação estava errada no final do dia, mas devemos corrigir essas peculiaridades em relação à bissimulação de sessão.

cc @johanstokking , @rvolosatovs

Todos 8 comentários

Sou a favor, como já discutimos.
O Application Server deve sempre confiar no Network Server, porque ele sempre possui os dados mais atualizados sobre a sessão do dispositivo.

  • Dispositivo final envia FPort = 0 uplink - AS não receberá este uplink

Não deveríamos mudar isso para que NS envie isso, mas com carga útil vazia e FPort 0, de modo que não seja enviado para o upstream?

  • Dispositivo final envia FPort = 0 uplink - AS não receberá este uplink

Não deveríamos mudar isso para que NS envie isso, mas com carga útil vazia e FPort 0, de modo que não seja enviado para o upstream?

É redundante, uma vez que a mensagem NS-> AS é assíncrona, a invalidação da fila pode chegar antes que o uplink FPort==0 seja enviado ao AS para confirmar a sessão, então temos que fazer isso de qualquer maneira. A única razão para enviar um uplink para o AS em resposta a FPort==0 uplink para o NS seria garantir que o AS seja notificado da mudança de sessão o mais rápido possível, mas não temos essa necessidade. Mesmo assim, faria muito mais sentido introduzir uma mensagem SessionSwitch , que NS enviaria para AS em vez do uplink FPort 0.

Eu atualizei a prioridade para prio/high pois ela está afetando v3.11.1 implantações.

As mudanças devem ser as seguintes:

  • Adicione SessionKeyID a DownlinkQueueInvalidation . Se a fila estiver vazia, o AS não pode saber neste momento qual fila foi invalidada.

A seguinte proto adição (campo 3 ) deve 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];
}
  • O AS deve atualizar a fila + FCnt da sessão correta, ao invés de sempre assumir que a invalidação é sobre dev.Session .

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

Em vez de usar dev.Session sempre, mude SessionKeyID para estabelecer qual sessão usar. Se necessário, atualize o dev.Session atual.

  • O AS deve verificar de qual sessão uma mensagem nacked é - é possível que a mensagem nacked seja de uma sessão pendente (da perspectiva do AS) e, como tal, a atualização do FCnt deve ser feita em a sessão correta.

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

Como antes, mude o SessionKeyID para determinar qual sessão usar. Se necessário, atualize o dev.Session atual.

  • (Opcional) retorne detalhes do erro em DownlinkQueue{Push|Replace} com o mínimo de FCnt e sempre atualize LastAFCntDown para este valor. Isso garantiria a convergência do sistema se, em algum ponto, ficarmos, por algum motivo, fora de sincronia entre AS e NS.

A seguinte adição proto deve ser preenchida e adicionada como detalhes do erro a errFCntTooLow no NS:

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

O AS pode então pegar esses detalhes e atualizar a sessão atual.

As alterações são compatíveis com versões anteriores e, esperançosamente, mínimas no lado do NS. O gênio já saiu da garrafa - todo o protocolo entre AS e NS lentamente se tornou assíncrono e simplesmente reverter a mudança FPort=0 não será suficiente. Não acho que essa transformação estava errada no final do dia, mas devemos corrigir essas peculiaridades em relação à bissimulação de sessão.

cc @johanstokking , @rvolosatovs

Parece bom para mim!

Posso fazer algo aqui? Em caso afirmativo, reatribua-me e me diga o quê.

Posso fazer algo aqui? Em caso afirmativo, reatribua-me e me diga o quê.

Já estou trabalhando nisso, com grande ênfase no seguinte ponto:

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

A razão para isso é que realizar ações com base nos eventos recebidos do NS, como parte da fila, fundamentalmente não é realmente suficiente:

  • As mensagens podem ser antigas, mas queremos fazer correções na fila _agora_
  • As mensagens podem ser perdidas - a fila não é infinita
  • As mensagens podem ser reordenadas - são colocadas de forma assíncrona na fila e são reordenadas de maneiras potencialmente reordenadas

Dadas essas características, existem duas opções:

  • Atrase o cálculo da fila até o final do processamento em lote (basicamente, se você receber 10 invalidações de fila de downlink, você recalcula a fila apenas no final). Isso não é suficiente pelos seguintes motivos:

    • Quando o AS processa um lote de mensagens, ele ainda não sabe se ele está _realmente_ no final da fila ou processando algum lote no meio

    • As mensagens ainda podem ser perdidas e determinar sua ordem não é trivial.

  • _Confie apenas no NS_. O que quero dizer com isso é que as operações de envio / substituição retornam dev.Session.SessionKeyID , dev.PendingSession.SessionKeyID e LastAFCntDown , como parte dos detalhes do erro. Em seguida, usamos os detalhes do erro para reconstruir a sessão no AS. Fundamentalmente, isso significa que quando tentamos fazer uma operação de fila de downlink, usando dados desatualizados (talvez uma sessão desatualizada, talvez um FCnt muito baixo), eventualmente convergimos para o estado NS. Pode levar uma, duas, três tentativas, vou fazer um limite para evitar girar infinitamente, mas pelo menos estamos operando com informações que são significativamente mais recentes do que a da fila de mensagens do uplink.
  • _Confie apenas no NS_. O que quero dizer com isso é que as operações de envio / substituição retornam dev.Session.SessionKeyID , dev.PendingSession.SessionKeyID e LastAFCntDown , como parte dos detalhes do erro. Em seguida, usamos os detalhes do erro para reconstruir a sessão no AS. Fundamentalmente, isso significa que quando tentamos fazer uma operação de fila de downlink, usando dados desatualizados (talvez uma sessão desatualizada, talvez um FCnt muito baixo), eventualmente convergimos para o estado NS. Pode levar uma, duas, três tentativas, vou fazer um limite para evitar girar infinitamente, mas pelo menos estamos operando com informações que são significativamente mais recentes do que a da fila de mensagens do uplink.

Acho que essa é a melhor opção.

Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

MatteMoveSRL picture MatteMoveSRL  ·  7Comentários

bafonins picture bafonins  ·  5Comentários

adamsondelacruz picture adamsondelacruz  ·  7Comentários

ecities picture ecities  ·  5Comentários

w4tsn picture w4tsn  ·  6Comentários