Você está na página 1de 4

UFMG

Redes
TP3 REDES
Alunos: Francisco Eli Rodrigues Lima
11 de Junho de 2018
Mariana Teatini Ribeiro

1 Desafios
O maior desafio neste trabalho foi o trade-off entre agrupar muita informação nas tabelas usadas no código e
ao mesmo tempo não deixá-lo muito complicado de manipular e achar possı́veis erros. O segundo desafio foi
manter o sincronismo dos dados, apesar de não haver problemas de concorrência sérios, precisávamos garantir
que não ocorresse situações inesperadas como ler estruturas vazias porque não foram preenchidas com os updates
corretos ou mesmo garantir duplicar entradas porque não houve tempo suficiente de fazer alguma checagem
importante.
Dificuldades do projeto: Um problema que consumiu um tempo razoável foi o não conhecimento da estru-
tura de dicionários de python, então na primeira implementação pensávamos que aquele formato dos pacotes
era simplesmente uma grande string com uma formato especı́fico, logo perdemos tempo criando funções que
codificavam e decodificavam pacotes, até percebemos que eles eram de fácil manipulação pela estrutura de
dicionários.

2 Atualizações periódicas:
Foi utilizada uma thread que roda um loop infinito a função abaixo, cada iteração do loop nós usamos duas
funções chamadas flush para limpar as entradas expiradas do vetor de distância de cada vizinho, que fica junto
da estrutura de dados que contém os vizinhos (NeighRoters), assim como limpamos também nosso próprio
vetor de distâncias (RouterList), dessa forma garantimos não mandar informações já expiradas para os nossos
vizinhos. Após isso, para cada vizinho criamos um pacote update especı́fico (create update pack ) e enviamos
para o destino com (udp send communication). Fazemos a thread adormecer por π segundos, conforme consta
na especificação como o tempo para mandar os pacotes de update. Ao final dos π segundos, a thread atualiza
novamente os vizinhos. Se um vizinho for removido ou adicionado, garantimos as atualizações corretas porque
simplesmente será removido da lista de Roteadores vizinhos.
def update_neighbors ( NeighRoters , routerList , myIp , mySock , pitime ):
while True :
flush_NeighList ( NeighRoters , t )
flush_routerList ( RoutersList , t )
for i in range ( len ( NeighRoters )):
destination = NeighRoters [ i ][0]
updatepack = create_update_pack ( dest , myIp , RoutersList )
ud p _ s e n d _ c o m m uni ca ti on ( destination , mySock , updatepack )
time . sleep ( pitime )

3 Split Horizon
A estratégia para garantir a otimização foi que ao criamos o pacote update para mandar para um vizinho, o que
se faz fazendo uma iteração sobre a tabela de distâncias (RoutersList) e adicionando distância por distância

• Se uma entrada nessa tabela de distâncias for igual ao destino do pacote de updates, então simplesmente
pulamos aquela iteração através de um comando continue.

• Em cada da tabela de distância RoutersList[i], guardamos uma lista de rotas possı́veis na 3 posição
RoutersLis[i][2] e pesquisamos sobre essa lista, se alguma dessas rotas for o destino do pacote update que
vamos mandar, então acionamos uma flag no código e simplesmente não colocamos mais tal entrada de
destinos, porque aprendemos daquele nó essa rota
• Dessa forma, nossos pacotes update obedecem à otimização split horizont

def cr ea te _update_pack ( dest , source , RoutersList ):


lista ={}
flag = False
for i in range ( len ( RoutersList )):
if ( RoutersList [ i ][0]== dest ):
continue

1
li s t o f _ o f _ p l a ce s_t o_ go = RoutersList [ i ][2]
for j in range ( len ( li sto f_ of _pl ac es _to _g o )):
if ( l i s t o f _ o f _ pl ace s_ to _go [ j ][0]== dest ):
flag = True
if ( flag == True ):
flag = False
continue
lista [ RoutersList [ i ][0]] = RoutersList [ i ][1]
lista [ source ] = 0
return { ’ type ’: ’ update ’ , ’ source ’: source , ’ destination ’: dest , ’ distances ’: lista }

4 Balanceamento de cargas
A estrutura da nossa tabela de distâncias RoutersList é a seguinte:

• Endereço do ip alcançável
• Distância até lá
• Lista de rotas com células da forma
• Ip da rota
• Tempo da rota aprendida(usado nas funções flush para retirar rotas desatualizadas).

isto é, para cada célula temos RoutersList = :

[destino1, distancia1, [[rota1, time1], [rota2, time2], . . . , [rotan, timen]]]


[destino2, distancia2, [[rota1, time1], [rota2, time2], . . . , [rotan, timen]]]
..
.
[destinon, distancian, [[rota1, time1], [rota2, time2], . . . , [rotan, timen]]]

Então toda vez que vamos procurar uma rota para algum destino,achamos o destino pelo primeiro campo,
simplesmente mandamos o pacote pela primeira entrada da lista de rotas daquela célula e jogamos essa entrada
para o final da lista, dessa forma garantimos uma divisão perfeita de fluxo.
Usamos a função search path para implementar tal abordagem
def s ea r c h_ p ath_routing ( destIp , RoutersList ):
for i in range ( len ( RoutersList )):
if ( RoutersList [ i ][0]== destIp ): # PROCURAMOS O IP DO DESTINO QUE QUEREMOS CHEGAR
aux = RoutersList [ i ][2] # PEGAMOS A TABELAS DE ROTA DAQUELE DESTINO
if ( len ( aux )==0):
return [ " not found " ," " ]
else :
aux1 = [ " found " , aux [0]]
aux . append ( aux [0]) # AQUI IMPLEMENTAMOS O BALANCEAMENTO
aux . remove ( aux [0]) # AQUI IMPLEMENTAMOS O BALANCEAMENTO
RoutersList [ i ][2]= aux # AQUI IMPLEMENTAMOS O BALANCEAMENTO
return aux1
return [ " not found " ," " ]

5 Reroteamento imediato
A nossa estrutura de vizinhos contém células da seguinte forma:
• Ip do vizinho
• Distância
• Uma lista com células da tabela de distância do vizinho
• Destino que o vizinho pode alcançar
• Distância para aquele destino

2
• Tempo em que descobrimos aquele destino alcançável pelo vizinho

[vizinho1, distancia1, [[destino1, distancia1, time1], . . . , [destinon, distancian, timen]]]


[vizinho2, distancia2, [[destino1, distancia1, time1], . . . , [destinon, distancian, timen]]]
..
.
[vizinhon, distancian, [[destino11, distancia1, time1], . . . , [destinon, distancian, timen]]]

Quanto precisamos achar uma rota alternativa, iteramos sobre todos os vizinhos e em cada vizino

• iteramos sobre sua tabela de distâncias, se acharmos uma pelo campo destino, então guardamos numa lista,
se acharmos novamente por outro vizinho uma rota por tamanho igual, adicionamos à lista novamente
• Se acharmos no passo anterior uma rota com tamanho menor, refazemos a lista apenas com aquele essa
rota menor.
• Ao final retornamos a lista com as rotas com menores distâncias possı́veis achadas. Tal procedimento é
implementado pela função search path rerouting

def s e a r c h _ p at h_re rout ing ( destIp , NeighRouters ):


distance =500000 # seta uma distancia grande
path = " " # colocamos nenhuma rota ainda
state = " not found " # inicialmente no achamos nada
t =0
for i in range ( len ( NeighRouters )): # ITERAMOS SOBRE A LISTA DE VIZINHOS
aux = NeighRouters [ i ][2] # pEGA A TABELA DE DISTANCIAS DO VIZINHO
for j in range ( len ( aux )): # itera sobre os roteadores # PROCURA SE ELE TEM AQUELE DESTINO
if ( aux [ j ][0]== destIp and aux [ j ][1] < distance ): # se acharmos a rota que queremos e a
path = NeighRouters [ i ][0] # distancia for menor , entao atualizamos
distance = aux [ j ][1]
state = " found "
t = aux [ j ][2]
return [ state , path , t ]

6 Remoção de rotas desatualizadas


Conforme foi vista anteriormente, temos dois lugares que precisamos checar para ver se as rotas estão atualizadas
ou não, basicamente seria muito custoso retirar uma rota imediatamente quando ela ficasse desatualizada porque
terı́amos que fazer uma busywait para conseguir chegar em algo próximo, então a estratégia utilizada foi toda
vez que fosse necessário saber quais são as rotas atualizadas para mandar um pacote, utilizamos duas funções
flush que procuram na tabela de distâncias e na tabela de vizinhos as rotas que já estão desatualizadas. A
estrutura da tabela de distancias e da tabela de vizinho foi vistas nos itens acima.
Vamos numa entrada da tabela de vizinhos e remove as rotas da tabela de distancias que já expiraram
def flush_Neighboor ( vizinho , pitime ):
tabela = vizinho [2] # aqui pega a tabela de distancia do no vizinho
i = 0
while ( i < len ( tabela )):
if ( time . time () > tabela [ i ][2]+4* pitime ): # aqui usamos o campo tempo ja explicado anteriormente
tabela . remove ( tabela [ i ]) # e vemos se ja estouramos 4 vezes aquele momento em tempo
else :
i +=1

Depois a lista de vizinhos removendo as rotas da tabela de distancias que já expiraram , utilizando a função
anterior pra remover
def flush_NeighList ( NeighList , pitime ):
for i in range ( len ( NeighList )):
flush_Neighboor ( NeighList [ i ] , pitime )

Já na nossa tabela de distâncias, analogamente à tabela de vizinhos


def flush_router ( router , t ):
tabela = router [2]
i = 0

3
while ( i < len ( tabela )):
if ( time . time () >4* t + tabela [ i ][1]):
tabela . remove ( tabela [ i ])
else :
i +=1

def flush_routerList ( RouterList , t ):


for i in range ( len ( RouterList )):
flush_router ( RouterList [ i ] , t )
i = 0
while ( i < len ( RouterList )):
if ( len ( RouterList [ i ][2])==0):
aux = s e a r c h _ p at h_re rout ing ( RoutersList [ i ][0] , NeighRoters )
if ( aux [0]== " found " ):
RouterList [ i ][2]. append ([ aux [1] , aux [2]])
else :
RouterList . remove ( RouterList [ i ])
i -=1
i +=1

Asssim, sempre que formos enviar um pacote e precisarmos procurar por rotas, damos um flush nas duas tabelas.
Também damos um flush nas duas tabelas no caso de precisarmos contruir um pacote update.