brtos / brtos-unet

0 stars 3 forks source link

Unicast Down Deadlock #3

Closed fabricio-godoi closed 7 years ago

fabricio-godoi commented 7 years ago

Olá,

Realizando alguns testes com a rede, verifiquei um caso de "deadlock" entre dispositivos, o cenário é o seguinte: Dado dois dispositivos X e Y, se X enviar uma mensagem para Y ao mesmo tempo em que Y tenta enviar uma mensagem para X (seja por aplicação ou mensagem de controle), ambos ficaram presos por causa do acesso ao buffer "packet_down". Na transmissão inicial, tanto X quanto Y travam o buffer para ninguém mais utilizar enquanto a mensagem não for enviada. Entretanto ao receber um pacote UNICAST na função unet_packet_input (unet_router.c), o processo tenta novamente travar o buffer para que seja possível enviar o ACK da rede, mas não vai conseguir, pois o buffer já está reservado para o processo de envio da mensagem. O que causa drop do pacote recebido. Com isso observou-se que: 1 - Esse comportamento foi análisado é ocorre mais de uma vez em locais diferentes da rede simulada; 2 - Esse fator realiza um efeito em cadeia, onde mais dispositivos podem ficar preso da mesma forma, até que algum ceda o buffer;

Em geral há o processo de tentativas e erros para desistir da transmissão, entretanto para o Unicast Down isso não ocorre devido a um incremente realizado no número de retentativas, linha 690 do arquivo unet_core.c na função UNET_Router_Down_Task. O que faz sentido, pois a mensagem foi entregue, portanto só não foi confirmado o ACK pela rede.

Com isso proponho três medidas de correção: 1 - seria enviar o ACK sem passar pelo buffer, pois não é uma informação que será propagada pela rede; 2 - criar um buffer único para pacotes do tipo ACK; 3 - retirar o incremento realizado na função UNET_Router_Down_Task. o que em tese resolve parcialmente o problema aplicanto número máximo de tentativas;

Segue uma foto do simulador com os pacotes presos no packet_down. Apresar de não estar nítido na imagem, o valor da variável status é 5 para ambos. Nota-se que foi deixada a simulação rodar por um tempo, verificando que ambos pacotes permanecem inalterados.

https://pasteboard.co/GFYFrTw.png

Obrigado pela atenção! Att. Fabricio

barriquello commented 7 years ago

Olá Fabrício,

obrigado por informar este problema. De fato isto pode acontecer qunado há uma inconsistência nas rotas.

Note que o caso X enviar um pacote down para Y e Y enviar um pacote down para X indica que algumas das rotas está errada, pois X é o pai de Y e Y é o pai de X. Portanto, há um loop momentâneo na rede.

Este loop será corrigido quando houver a troca de pai de X ou de Y para outro nó (ex.: Z). Mas, de fato, o pacote que já está no buffer ficará com o endereço do pai antigo e isto é um bug.

Para corrigir teria que trocar o endereço do pacote down que está no buffer se houver a troca do pai (isto é, caso a função link_parent_switch() em link.c seja chamada. Aí o endereço do pacote no buffer down deve ser alterado (ex. para Z) e o pacote eventualmente será entregue para Z, desfazendo o deadlock.

As outras soluções que você indicou tem o seguintes problemas:

1 - seria enviar o ACK sem passar pelo buffer, pois não é uma informação que será propagada pela rede;

R: o buffer que está ocupado é o do packet down. O buffer do ack packet down (que é o buffer de ack) está livre. Então, isto não vai resolver o problema.

2 - criar um buffer único para pacotes do tipo ACK;

R: isto já existe. Há dois buffers exclusivos de ACK (o Radio_TX_ACK_up_buffer e Radio_TX_ACK_down_buffer)

3- retirar o incremento realizado na função UNET_Router_Down_Task. o que em tese resolve parcialmente o problema aplicanto número máximo de tentativas;

R: isto pode ser feito, mas pode causar perda de pacotes na rede. Se a solução de trocar o pai no pacote for difícil de ser implementada (acho que não é tão difícil), esta solução pode funcionar para destravar o deadlock. Mas isso vai causar a perda do pacote.

fabricio-godoi commented 7 years ago

Olá Barriquello,

Assim como você disse, os métodos que propus não faziam sentido, me confundi ao sugerir isso. Fiz algo parecido com o que você sugeriu, na própria função UNET_Router_Down_Task, no local a onde há o incremento, realizei mais um teste com o pacote, de forma a verificar se a rota do "parent" foi alterada. Ou seja, verifico se destino de 16 bits (next hop) é igual ao parent configurado. Dessa forma se for diferente eu simplesmente realizo a alteração do destino do pacote para o parent configurado.

Testei dessa forma a aparentemente não houve mais problemas de deadlock.

As alterações que estou realizando se encontra disponível em: https://github.com/fabricio-godoi/unet4cooja

Obrigado pela ajuda! Att. Fabrício

barriquello commented 7 years ago

Olá Fabrício,

acho que esta sua solução deve funcionar. Se você me enviar um pull request com sua modificação, já adiciono no projeto. Para isto você pode fazer um fork do projeto brtos-unet no github, fazer a alteração no código, dar um push, e no github criar o pull request.