È un protocollo che detta la costruzione delle tabelle di routing per il routing intra-dominio (cioè localmente a singola rete).

È implementato come applicazione sopra UDP (User Datagram Protocol) sulla porta 520. È eseguito nel processo chiamato “routed” di ogni router. Questi processi comunicano fra loro scambiandosi i messaggi per costruire le tabelle di routing.

Il contesto in cui opera è il grafo della rete, in cui i nodi sono i router. Le tabelle di routing possono essere semplificate in array di distanze dal nodo corrente agli altri nodi.

L’algoritmo si basa sulla formula di Bellman-Ford

Dove è la “distanza” da a , è un vicino di e è il costo dell’arco .

N.B.: Nel protocollo RIP i costi/distanze degli archi sono tutti unari per definizione.

Algoritmo per la creazione del vettore dei costi

L’esecuzione è iterativa, distribuita e asincrona.

  • Ogni nodo crea un vettore con i costi dei nodi vicini direttamente collegati ad esso inviando loro dei messaggi di hello; i costi non noti sono inizializzati a . Dopodiché invia una copia del vettore ai suoi vicini.
  • Quando un nodo riceve un nuovo vettore da uno dei suoi vicini, lo salva e usa la formula di Bellman-Ford per aggiornare tutte le distanze.
    • Se c’è stato almeno un cambiamento nel vettore, il nodo manda a tutti i suoi vicini il vettore aggiornato.

N.B.: Nel protocollo RIP .

Problema e soluzioni

Se si guasta il collegamento con un router, disconnettendolo dalla rete, servono molte iterazioni fino a che il suo costo nel vettore venga incrementato fino a 16.

Soluzione Split horizon

Un router non annuncia mai un costo allo stesso router da cui l’ha appreso.

Miglioramento con poisoned reverse: invece di nascondere il cammino, il router lo annuncia esplicitamente come non valido (costo = 16).

Messaggi RIP

Comandi:

  • RIP request quando il router viene inserito,
  • RIP response (solicited) in risposta a una request,
  • RIP response (unsolicited) ogni 30 secondi (timer periodico),

Campi del messaggio:

  • header, fatto da:
    • comando (richiesta 1, risposta 2),
    • versione,
  • una o più entry della tabella di routing, fatta da (campi più importanti):
    • indirizzo IP del nodo,
    • maschera di sottorete,
    • indirizzo del prossimo hop,
    • distanza.

Altri timer

  • Timer di scadenza: se entro 180 secondi non si riceve l’aggiornamento da un nodo, il suo percorso è considerato scaduto e il suo costo è impostato a 16. Hold-down: Si fa partire un timer che ignora gli aggiornamenti per quel percorso per un tempo stabilito.
  • Timer per garbage collection: ogni 120 secondi elimina i percorsi dalla tabella con costo pari a 16.

N.B.: Quando si riceve un cambiamento si invia immediatamente la tabella ai vicini senza attendere il timeout.

Simulazione in Python

class Router:
    def __init__(self, name: str):
        self.name = name
        self.table = {self: 0}
        self.neighbours = {}
 
    def connect(self, neighbours: Set[Router]):
        self.neighbours = neighbours
        for r in neighbours:
            if r not in self.table:
                self.table[r] = 1
            if self not in r.table:
                r.table[self] = 1
 
    def notify(self):
        for r in self.neighbours:
            print(f'{self.name} sended table to {r.name} > ', end = '')
            r.receive_update(self.table)
 
    def receive_update(self, neighbour_table):
        old_table = self.table.copy()
        for r in neighbour_table:
            if r != self:
                if r not in self.table:
                    self.table[r] = neighbour_table[r] + 1
                self.table[r] = min(self.table[r], 1 + neighbour_table[r])
        if old_table != self.table:
            print(f'{self.name} was updated: {self.name} = {self.table}')
            self.notify()
        else:
            print(f'{self.name} not updated')
 
    def __str__(self):
        return self.name
 
    def __repr__(self):
        return self.name
 
 
if __name__=='__main__':
    r = {x: Router(x) for x in 'ABCDEFGHI'}
 
    r['A'].connect({r['B'], r['C'], r['D'], r['I']})
    r['B'].connect({r['A'], r['C'], r['G'], r['F'], r['H']})
    r['C'].connect({r['A'], r['B'], r['D']})
    r['D'].connect({r['A'], r['C'], r['E'], r['G']})
    r['E'].connect({r['D'], r['F'], r['I']})
    r['F'].connect({r['B'], r['E']})
    r['G'].connect({r['B'], r['D']})
    r['H'].connect({r['F'], r['B']})
    r['I'].connect({r['A'], r['E']})
 
    r['A'].notify()
 
    print('\nresults:')
    for router in r.values():
        print(f'{router.name} = {router.table}')