D'après le principe utilisé dans le protocole RIP, un routeur va "explorer" la table de routage de ses voisins directs :
None
comme passerelle ( le lien est direct ), et un nombre de saut de 1. Il faut bien entendu, vérifier que la destination n'est pas le routeur lui-même : un routeur n'apparaît pas dans sa propre table de routage !
class Routeur:
def __init__(self, nom: str):
self.nom = nom
self.table = {}
def get_nom(self)->str:
return str(self.nom)
def get_table(self)->dict:
return self.table
def maj_table(self, voisin):
nom_voisin = voisin.get_nom()
"""Voisin pas encore dans la table :
Nouvelle entrée :
voisin: ['', 1]
"""
if nom_voisin not in self.table:
self.table[nom_voisin] = ['', 1]
"""sinon, récupération de la table de routage
du routeur, et maj des distances
si nécessaire
"""
else:
table_voisin = voisin.get_table()
for destination in table_voisin:
"""pour les entrées qui ne concernent pas le routeur
lui-même
"""
if destination != self.nom:
"""Découverte d'une nouvelle destination :
Nouvelle entrée dans la table de routage :
destination: [routeur voisin, sauts depuis le voisin + 1]
Le nombre de sauts vers une destination est le 2ème élément
du tableau d'une destination dans la table de routage.
"""
if destination not in self.table:
self.table[destination] = [nom_voisin, table_voisin[destination][1]+1]
"""sinon ( la destination est déjà dans la table ),
maj de la distance si celle-ci est plus petite
que celle dans la table
"""
else:
nv_distance = table_voisin[destination][1]+1
if nv_distance < self.table[destination][1]:
self.table[destination] = [nom_voisin, nv_distance]
On remarque que c'est bien un objet Routeur
que prend la méthode maj_table
comme paramètre, pas seulement le nom d'un routeur...
rip
Rien de compliqué : on parcourt la liste des routeurs du réseau, et on envoie chacun de leurs voisins comme argument à leur méthode maj_table
:
def rip(reseau):
for routeur in reseau: # pour chaque routeur dans le réseau
for voisin in reseau[routeur]: # pour chacun de ces voisins
routeur.maj_table(voisin) # on envoie le voisin en argument au routeur courant
Bien se souvenir qu'un routeur est un objet, à stocker dans une variable pour pouvoir ensuite le réutiliser :
r1 = Routeur('R1')
r2 = Routeur('R2')
r3 = Routeur('R3')
r4 = Routeur('R4')
r5 = Routeur('R5')
r6 = Routeur('R6')
r7 = Routeur('R7')
reseau = {
r1: [r2, r3],
r2: [r1, r3, r4],
r3: [r1, r2, r5],
r4: [r2, r5, r6],
r5: [r3, r4, r6, r7],
r6: [r4, r5, r7],
r7: [r5, r6]
}
for i in range(3):
print(f"RIP n°{i+1}")
print('-----------------')
for r in reseau:
print(r.get_nom(), ':')
for dest, ligne in r.get_table().items():
print(dest, ':', ligne)
print()
print('-----------------')
print()
rip(reseau)
Les tables de routage se stabilisent très vite ( le réseau est petit...).
def incident(reseau, defaut):
reseau[defaut] = [] # on supprime tous les liens depuis le routeur en défaut
nom_defaut = defaut.get_nom()
for routeur in reseau: # pour chaque routeur dans le réseau
if defaut in reseau[routeur]: # si le routeur en défaut est dans la liste d'adjacence du routeur courant,
reseau[routeur].remove(defaut) # on supprime le routeur en défaut de cette liste.
for destination in routeur.table: # pour chaque destination dans la table de routage du routeur courant,
if destination == nom_defaut or routeur.table[destination][0] == nom_defaut: # si le routeur en défaut est la destination, ou si la destination passe par lui,
routeur.table[destination][1] = 16 # alors on met la distance à 16.
Après avoir simulé un incident, par exemple en désactivant R5, on observe bien la mise à jour des tables de routage, qui passent maintenant par R6.