Salta al contenuto
Note per Studenti Algoritmi di instradamento - link state e distance vector

Algoritmi di instradamento - link state e distance vector

In questa pagina 6
In questa pagina 6

Il livello di rete (Livello di rete e indirizzamento IPIl livello di rete (network layer) porta i datagrammi da host a host attraverso i router: incapsula (framing), sceglie il percorso (routing) e sposta il pacchetto da un ingresso a un'uscita del router (forwarding); in Internet lascia ai livelli superiori controllo d'errore, di flusso e di congestione. Un indirizzo IPv4 è di 32 bit, diviso in prefisso (rete, $n$ bit) e suffisso (host, $32-n$ bit). L'indirizzamento a classi (A, B, C, D, E) è obsoleto; oggi si usa quello senza classi (CIDR): data una notazione $a.b.c.d/n$ si ricavano $N=2^{32-n}$ indirizzi, indirizzo di rete (suffisso tutto 0) e di broadcast (suffisso tutto 1), oppure con la netmask: rete $=$ indirizzo AND maschera, broadcast $=$ indirizzo OR (NOT maschera).Livello di rete e indirizzamento IP →) ha due compiti distinti: l'instradamento (routing), cioè calcolare quale strada seguire, e l'inoltro (forwarding), cioè spostare ogni pacchetto verso l'interfaccia di uscita indicata dalla tabella (Instradamento e inoltroL'inoltro (forwarding) mette il pacchetto sulla strada verso la destinazione, un salto alla volta (hop by hop). Se la destinazione è nella stessa rete del mittente l'inoltro è diretto (si usa l'ARP per il MAC del destinatario), altrimenti è indiretto: il pacchetto va al router successivo (next hop) indicato dalla tabella di instradamento, o al default gateway. Con le netmask: l'inoltro è diretto attraverso l'interfaccia $x$ se $\text{IP(dst)}\ \text{AND}\ \text{NM}(x)=\text{IP}(x)\ \text{AND}\ \text{NM}(x)$; altrimenti si scorre la tabella dalla maschera più lunga (longest prefix match) e si usa il primo match. La riga con rete $0.0.0.0$ e maschera $0.0.0.0$ (default route) corrisponde sempre. L'aggregazione di rotte (route aggregation) riduce la tabella, e nell'inoltro con etichette (MPLS) la tabella si consulta per indice.Instradamento e inoltro →). Questa nota tratta il primo: come i router riempiono le loro tabelle. I protocolli veri e propri che usano questi algoritmi (RIP, OSPF, BGP) sono in Protocolli di instradamento - RIP, OSPF e BGPIn Internet l'instradamento non si può fare con un solo protocollo, per scalabilità (tabelle troppo grandi) e per autonomia amministrativa: ogni ISP è un sistema autonomo (AS) con il proprio algoritmo. All'interno di un AS si usano i protocolli IGP: RIP (distance vector, numero di salti, massimo 15, aggiornamenti ogni circa 30 s, su UDP porta 520) e OSPF (link state con Dijkstra, aree collegate all'area 0, cinque tipi di LSA, messaggi direttamente in IP). Tra AS si usa BGP4 (path vector, su TCP porta 179, eBGP tra AS e iBGP dentro l'AS, scelta del percorso per politica: preferenza locale, AS-PATH più corto, origine; i cicli si evitano scartando i cammini che contengono già il proprio AS; quattro messaggi: Open, Keepalive, Notification, Update).Protocolli di instradamento - RIP, OSPF e BGP →.

Il problema: trovare il percorso migliore

Definizione (instradamento). L'insieme delle procedure che permettono di determinare un percorso da un punto a un altro. È possibile solo se ogni router ha una tabella di inoltro per mandare il datagramma al nodo successivo (next hop) sulla strada verso la destinazione.

Perché il percorso conta: instradamento e capacità

In una rete a maglia la quantità di traffico consegnabile dipende da come i flussi sono instradati, non solo dalla capacità dei collegamenti. Si abbiano due flussi S1→D1S_1\to D_1 e S2→D2S_2\to D_2 e collegamenti tutti di capacità CC:

  • se i due flussi usano gli stessi collegamenti, condividono la capacità e il traffico massimo consegnato in totale è CC;
  • se i flussi sono distribuiti su percorsi diversi (nell'esempio delle slide ci sono tre collegamenti utilizzabili in parallelo), il traffico massimo sale a 3C3C.

Un buon algoritmo di instradamento non cerca soltanto "una strada" ma una strada che usi bene la rete.

La rete come grafo pesato

Per trovare il percorso migliore un insieme di reti interconnesse (internet) si modella come grafo pesato (nodi, archi, cammini e connessione sono definiti in Grafi - definizioni e proprietàGrafo G=(V,E) diretto e non diretto, grafo semplice e pesato; incidenza, adiacenza, grado; cammini, cicli, sottografi, grafi connessi e componenti connesse; alberi liberi, foreste, spanning tree e spanning forest; proprietà con dimostrazioni (somma dei gradi = 2m, m <= n(n-1)/2, alberi m = n-1, connessi m >= n-1, foreste m <= n-1).Grafi - definizioni e proprietà →): ogni router è un nodo, ogni rete tra due router è un arco, e a ogni arco è associato un costo. Se tra due nodi non c'è un arco il costo è ∞\infty. Il significato del costo cambia da protocollo a protocollo.

Definizione (percorso di costo minimo). Dato un grafo connesso G=(V,E)G=(V,E) e una funzione di costo additiva (il costo di un cammino è la somma dei costi degli archi), il percorso di costo minimo (least-cost route, LCR) da una sorgente ss a un nodo vv è la sequenza di nodi connessi, da ss a vv, con somma dei costi minima fra tutti i cammini possibili.

Ogni router deve trovare il percorso di costo minimo verso tutti gli altri router: con NN router sono N−1N-1 percorsi per ciascuno, cioè N(N−1)N(N-1) percorsi in tutta la rete. Conviene raccoglierli in un albero di costo minimo (least-cost tree): un albero che ha il router sorgente come radice, tocca tutti gli altri nodi e in cui il cammino dalla radice a ogni nodo è quello minimo. Si ha così un solo albero per sorgente, quindi NN alberi per tutta la rete.

Quale costo? Le metriche

"Migliore" non ha un'unica risposta: minimo numero di salti, minimo ritardo end-to-end, minima probabilità di perdita, massimo throughput a lungo termine. Per far calcolare a Dijkstra o a Bellman-Ford il percorso desiderato basta scegliere bene il costo ci,jc_{i,j} di ogni coppia di nodi collegati:

criterio costo ci,jc_{i,j} dell'arco spiegazione
minimo numero di salti (hop count) ci,j=1c_{i,j}=1 il costo del cammino è il numero di archi
minimo ritardo end-to-end ci,j=Li,j/Ri,j+tp(i,j)c_{i,j}=L_{i,j}/R_{i,j}+t_p(i,j) tempo di trasmissione del pacchetto più propagazione
minima probabilità di perdita ci,j=−log⁡Pok(i,j)c_{i,j}=-\log P_{ok}(i,j) il prodotto delle probabilità di successo diventa una somma di logaritmi (proprietà in Esponenziale e logaritmoLa funzione esponenziale a^x (base positiva diversa da 1) e la sua inversa, il logaritmo in base a, con grafici e proprietà.Esponenziale e logaritmo →)
massimo throughput ci,j=1/Ri,j nc_{i,j}=1/R_{i,j}^{\,n}, con n>1n>1 intero vedi sotto

Esempio (ritardo). Pacchetto di L=1500L=1500 byte =12 000=12\,000 bit su un collegamento da R=10R=10 Mbit/s con propagazione tp=2t_p=2 ms: c=12 000/107 s+2 ms=1,2+2=3,2c=12\,000/10^7\ \text{s}+2\ \text{ms}=1{,}2+2=3{,}2 ms.

Esempio (perdite). Due collegamenti con Pok=0,9P_{ok}=0{,}9 e 0,80{,}8: la probabilità di successo sul cammino è 0,9⋅0,8=0,720{,}9\cdot0{,}8=0{,}72. Con i costi logaritmici si ottiene la stessa informazione per somma: −ln⁡0,9−ln⁡0,8=0,1054+0,2231=0,3285=−ln⁡0,72-\ln0{,}9-\ln0{,}8=0{,}1054+0{,}2231=0{,}3285=-\ln0{,}72. Minimizzare la somma dei costi equivale quindi a massimizzare la probabilità di successo. I passaggi: (1) la probabilità di successo di un cammino è il prodotto P=∏Pok(i,j)P=\prod P_{ok}(i,j) (i collegamenti perdono in modo indipendente: Indipendenza di eventiA e B sono indipendenti se P(A ∩ B) = P(A) P(B), cioè se sapere che uno si è verificato non cambia la probabilità dell'altro; l'indipendenza passa ai complementari, non va confusa con l'incompatibilità, e per più eventi va richiesta su ogni sottofamiglia.Indipendenza di eventi →); (2) il logaritmo trasforma il prodotto in somma, ln⁡(ab)=ln⁡a+ln⁡b\ln(ab)=\ln a+\ln b; (3) poiché 0<Pok≤10<P_{ok}\le1 si ha ln⁡Pok≤0\ln P_{ok}\le0, e il segno meno rende ogni costo c≥0c\ge0, come richiede Dijkstra; (4) il logaritmo è crescente, quindi PP massima equivale a ln⁡P\ln P massimo, cioè −ln⁡P=∑ci,j-\ln P=\sum c_{i,j} minimo.

Perché per il throughput serve un trucco. Il throughput a lungo termine di un cammino è il minimo dei bitrate lungo il cammino (il collo di bottiglia), non la loro somma: la condizione di additività richiesta da Dijkstra non vale e il massimo throughput non si può riprodurre esattamente. Si può però approssimare con c=1/Rnc=1/R^n e nn grande: elevando alla nn si amplifica il peso del collegamento più lento, così che il cammino più corto sia quasi sempre quello con il collo di bottiglia migliore.

Esempio. Un cammino PP di 10 collegamenti da 100 Mbit/s (collo di bottiglia 100) e un cammino QQ di due collegamenti da 50 e 100 Mbit/s (collo di bottiglia 50). Con n=1n=1: P=10/100=0,1P=10/100=0{,}1, Q=1/50+1/100=0,03Q=1/50+1/100=0{,}03: vince QQ, sbagliando. Con n=3n=3: P=10−5P=10^{-5}, Q=9⋅10−6Q=9\cdot10^{-6}, ancora QQ. Con n=6n=6: P=10⋅100−6=10−11P=10\cdot100^{-6}=10^{-11}, Q=50−6+100−6=6,5⋅10−11Q=50^{-6}+100^{-6}=6{,}5\cdot10^{-11}: vince PP, correttamente.

Instradamento statico e dinamico

  • Statico (reti piccole): le tabelle sono compilate a mano; non reagiscono a guasti o cambi di topologia. Si possono definire più cammini statici tra due nodi per avere un po' di resilienza.
  • Dinamico (reti grandi): un protocollo aggiorna da solo le tabelle quando cambiano carico o topologia. Costo: i protocolli generano traffico di controllo, e durante i transitori le tabelle dei nodi possono non essere coerenti (rischio di instabilità).

Le tre famiglie di algoritmi

link state distance vector path vector
algoritmo Dijkstra Bellman-Ford alberi di copertura (spanning tree) con politica
informazione che serve topologia completa solo i vicini solo i vicini
cosa si scambia informazioni locali (i propri collegamenti) con tutti i nodi informazioni globali (le distanze verso tutti) con i soli vicini cammini interi con i soli vicini
calcolo centralizzato sul grafo intero iterativo e distribuito iterativo e distribuito
obiettivo cammino di costo minimo cammino di costo minimo raggiungibilità secondo politiche
protocolli OSPF, IS-IS RIP, IGRP BGP

Ogni nodo deve prima conoscere i vicini e identificarli (pacchetti HELLO), poi calcolare il costo dei collegamenti diretti, i costi locali (per esempio con pacchetti ECHO per misurare il ritardo). Con queste informazioni crea un pacchetto, il Link State Packet (LSP), e lo diffonde a tutti gli altri router con un flooding (una specie di broadcast multi-salto), da ripetere dopo ogni cambiamento dello stato di un collegamento. Quando un router ha ricevuto l'LSP di ogni nodo, ha l'intero grafo e applica Dijkstra per ottenere il percorso minimo verso ogni altro nodo.

Formato dell'LSP: nome della sorgente seguito da coppie (vicino, costo).

Esempio. Rete con sette router A,…,GA,\dots,G e archi A ⁣− ⁣B=4A\!-\!B=4, A ⁣− ⁣F=1A\!-\!F=1, B ⁣− ⁣C=2B\!-\!C=2, B ⁣− ⁣G=1B\!-\!G=1, C ⁣− ⁣D=3C\!-\!D=3, C ⁣− ⁣G=4C\!-\!G=4, D ⁣− ⁣E=6D\!-\!E=6, E ⁣− ⁣F=3E\!-\!F=3, F ⁣− ⁣G=1F\!-\!G=1.

Grafico interattivo: Rete di esempio con i costi dei collegamenti

Ogni router ha ricevuto questi sette LSP:

sorgente vicino e costo
A B 4, F 1
B A 4, C 2, G 1
C B 2, D 3, G 4
D C 3, E 6
E F 3, D 6
F A 1, G 1, E 3
G B 1, C 4, F 1

Leggendo la tabella un nodo qualsiasi ricostruisce il grafo della figura (ogni arco compare due volte, una per estremo). Su questo grafo applica Dijkstra.

L'algoritmo di Dijkstra

(L'algoritmo è presentato anche come problema sui grafi in Cammini minimi e algoritmo di DijkstraGrafi pesati, lunghezza di un cammino e distanza; sottocammini di un cammino minimo; problema SSSP; algoritmo di Dijkstra con cloud e priority queue, rilassamento degli archi, esempio svolto; correttezza (due lemmi) e complessità O(min(n^2, (n+m) log n)) con lista non ordinata o heap; pesi non negativi.Cammini minimi e algoritmo di Dijkstra →; qui è letto dal punto di vista del router.) L'obiettivo è trovare il percorso più breve da un nodo di partenza ss (starting node) a tutti gli altri (one-to-all). L'algoritmo parte con valori iniziali per la distanza da ss e a ogni passo li migliora, determinando a ogni passo la distanza minima di un nodo.

Definizione (stato di un nodo in Dijkstra). Ogni nodo ℓ\ell ha uno stato (dℓ, p oppure t)(d_\ell,\ p\text{ oppure }t):

  • dℓd_\ell è la stima corrente della distanza da ss (il costo accumulato);
  • l'etichetta è permanente (pp) se dℓd_\ell è già la distanza minima da ss, temporanea (tt) altrimenti.

A ogni passo un nodo è il nodo corrente.

Passi:

  1. Inizializzazione. Lo stato di ss è (0,p)(0,p) e ss è il nodo corrente. Ogni altro nodo ha stato (∞,t)(\infty,t).
  2. Rilassamento. Per ogni vicino vv del nodo corrente uu non ancora permanente si calcola dv=min⁡{dv, du+cu,v}d_v=\min\{d_v,\ d_u+c_{u,v}\}; se il minimo è la seconda quantità, si aggiorna anche il predecessore di vv (puntatore a uu).
  3. Scelta. Tra i nodi temporanei si sceglie quello con dd minima: diventa permanente e nodo corrente. Si torna al passo 2 finché non restano nodi temporanei raggiungibili. Perché quel nodo è definitivo: qualunque altra strada verso di lui dovrebbe passare per un altro nodo temporaneo, che ha già una stima almeno uguale, e da lì i costi (non negativi) possono solo aumentare; la dimostrazione precisa è nella sezione sulla correttezza.
  4. Dai predecessori ai cammini. Per conoscere il cammino da ss a vv si segue la catena dei predecessori da vv a ss e la si legge al contrario.

Pseudocodice (con dist e prev):

Dijkstra(Graph, source):
   per ogni vertice v: dist[v] = INFINITO; prev[v] = NON DEFINITO; v entra in Q
   dist[source] = 0
   finche' Q non e' vuoto:
       u = vertice di Q con dist minima; togli u da Q
       per ogni vicino v di u ancora in Q:
           alt = dist[u] + length(u, v)
           se alt < dist[v]:  dist[v] = alt;  prev[v] = u
   restituisci dist[], prev[]

Esempio 1 (grafo a 6 nodi, sorgente 1). Archi: 1 ⁣− ⁣2=71\!-\!2=7, 1 ⁣− ⁣3=91\!-\!3=9, 1 ⁣− ⁣6=141\!-\!6=14, 2 ⁣− ⁣3=102\!-\!3=10, 2 ⁣− ⁣4=152\!-\!4=15, 3 ⁣− ⁣4=113\!-\!4=11, 3 ⁣− ⁣6=23\!-\!6=2, 4 ⁣− ⁣5=64\!-\!5=6, 5 ⁣− ⁣6=95\!-\!6=9.

passo nodo corrente (diventa permanente) stati dei nodi ancora temporanei (distanza, predecessore)
1 1, con d=0d=0 2:(7,1)2:(7,1), 3:(9,1)3:(9,1), 6:(14,1)6:(14,1), 4:∞4:\infty, 5:∞5:\infty
2 2, con d=7d=7 (il minimo è 7) 33 resta min⁡{9, 7+10}=9\min\{9,\,7+10\}=9; 4:( 7+15=22, 2)4:(\,7+15=22,\,2); 6:(14,1)6:(14,1); 5:∞5:\infty
3 3, con d=9d=9 6:min⁡{14, 9+2}=(11,3)6:\min\{14,\,9+2\}=(11,3); 4:min⁡{22, 9+11}=(20,3)4:\min\{22,\,9+11\}=(20,3); 5:∞5:\infty
4 6, con d=11d=11 5:(11+9=20, 6)5:(11+9=20,\,6); 4:(20,3)4:(20,3)
5 5, con d=20d=20 (pari merito con 4: si può scegliere uno qualsiasi dei due) 4:min⁡{20, 20+6}=204:\min\{20,\,20+6\}=20, invariato
6 4, con d=20d=20 nessuno

Distanze da 1: d2=7d_2=7, d3=9d_3=9, d6=11d_6=11, d4=20d_4=20, d5=20d_5=20. Cammino da 1 a 5: predecessore di 5 è 6, di 6 è 3, di 3 è 1: leggendo al contrario 1→3→6→51\to3\to6\to5, costo 9+2+9=209+2+9=20. Cammino da 1 a 4: predecessore di 4 è 3: 1→3→41\to3\to4, costo 9+11=209+11=20.

Esempio 2 (il grafo A,…,GA,\dots,G, sorgente AA). Ogni riga è lo stato dopo che il nodo indicato è diventato permanente; in ogni cella: distanza e predecessore.

passo permanenti B C D E F G
0 {A}\{A\} 4-A ∞\infty ∞\infty ∞\infty 1-A ∞\infty
1 {A,F}\{A,F\} 4-A ∞\infty ∞\infty 4-F 1-A 2-F
2 {A,F,G}\{A,F,G\} 3-G 6-G ∞\infty 4-F 2-F
3 {A,F,G,B}\{A,F,G,B\} 3-G 5-B ∞\infty 4-F
4 +E+E 5-B 10-E 4-F
5 +C+C 5-B 8-C
6 +D+D 8-C

Spiegazione dei passi cruciali: al passo 1 da FF si raggiunge GG con 1+1=21+1=2 e EE con 1+3=41+3=4; al passo 2 da GG si migliora BB (2+1=3<42+1=3<4) e si trova CC (2+4=62+4=6); al passo 3 da BB si migliora CC (3+2=5<63+2=5<6); al passo 4 EE (distanza 4, minore di 5) fa raggiungere DD con 4+6=104+6=10; al passo 5 CC migliora DD (5+3=8<105+3=8<10).

Albero di costo minimo di AA (archi in colore): A ⁣− ⁣FA\!-\!F, F ⁣− ⁣GF\!-\!G, G ⁣− ⁣BG\!-\!B, B ⁣− ⁣CB\!-\!C, C ⁣− ⁣DC\!-\!D, F ⁣− ⁣EF\!-\!E.

Grafico interattivo: Albero di costo minimo di A (archi colorati)

(le etichette sugli archi dell'albero sono le distanze da AA, non i costi degli archi; i tratteggi sono archi che esistono ma non fanno parte dell'albero.)

Dall'albero alla tabella di AA. Il next hop verso ogni destinazione è il primo nodo del cammino: verso GG, BB, CC, DD, EE e FF si passa tutti da FF (per BB: A→F→G→BA\to F\to G\to B).

destinazione costo next hop
B 3 F
C 5 F
D 8 F
E 4 F
F 1 F
G 2 F

Ogni router esegue Dijkstra per conto proprio, con sé stesso come sorgente, ottenendo il proprio albero e la propria tabella.

Complessità. Con la scelta del minimo tra i nodi temporanei fatta scorrendo l'elenco si fanno nn scelte di costo O(n)O(n) ciascuna, quindi O(n2)O(n^2) (Notazione asintoticaDefinizioni di O, Omega, Theta e o piccolo con le costanti c ed n0; esempi con costanti esplicite; proprietà (polinomi, esponenziali, logaritmi, somme, implicazioni tra notazioni); sommatorie notevoli; terminologia (logaritmica, lineare, polinomiale, esponenziale).Notazione asintotica →: il numero di operazioni cresce come il quadrato di nn); con una coda con prioritàstruttura dati che restituisce l'elemento di chiave minima in tempo logaritmicoCode con priorità → si arriva a O((n+m)log⁡n)O((n+m)\log n), con mm numero di archi. Conti: ogni nodo diventa permanente una volta (nn volte la ricerca del minimo, O(n)O(n) ciascuna, quindi n⋅nn\cdot n), e ogni arco viene rilassato al più una volta per estremo (O(m)O(m) rilassamenti); con la coda ogni estrazione o aggiornamento costa O(log⁡n)O(\log n).

Distance vector

Qui nessun nodo conosce la topologia. Ogni nodo parte conoscendo solo i vicini (con i pacchetti HELLO e ECHO come sopra) e costruisce un vettore delle distanze (distance vector, DV): per ogni destinazione, la distanza e il next hop del percorso minimo attualmente noto.

Esempio (DV di AA all'inizio).

destinazione distanza next hop
A 0 -
B 4 B
C ∞\infty -
D ∞\infty -
E ∞\infty -
F 1 F
G ∞\infty -

Questi vettori rudimentali non bastano a inoltrare bene i pacchetti: sono i percorsi minimi con le informazioni limitate che un nodo ha. Per migliorarli i nodi devono aiutarsi: periodicamente (a intervalli casuali tra 25 e 35 s) oppure quando il proprio DV cambia, ogni nodo manda il suo DV ai vicini. Quando un nodo riceve il DV di un vicino, aggiorna il proprio con un algoritmo distribuito (Bellman-Ford). Dopo un transitorio i DV convergono ai veri percorsi minimi. Se una riga non viene aggiornata entro un certo tempo (expiration timer, 180 s) il costo verso quella destinazione diventa infinito; dopo altri 120 s (garbage collection) la riga è cancellata.

Formula (aggiornamento di Bellman-Ford). Il nodo AA riceve dal vicino YY il DV con le stime dY,wd_{Y,w} del costo da YY a ogni destinazione ww. Per ogni ww: DA,w=min⁡{ DA,w, DA,Y+dY,w }.D_{A,w}=\min\{\,D_{A,w},\ D_{A,Y}+d_{Y,w}\,\}. Se il valore passando per YY è minore, si mettono nella riga ww il nuovo costo e next hop =Y=Y.

Qui DA,YD_{A,Y} è il costo immediato del collegamento A→YA\to Y e dY,wd_{Y,w} è il costo minimo stimato da YY a ww (che può passare per più salti).

Esempio. AA riceve da BB il primo DV di BB, che dice dB,A=4d_{B,A}=4, dB,C=2d_{B,C}=2, dB,G=1d_{B,G}=1 e ∞\infty per DD, EE, FF. Con DA,B=4D_{A,B}=4: per CC, min⁡{∞, 4+2}=6\min\{\infty,\,4+2\}=6 (next hop BB); per GG, min⁡{∞, 4+1}=5\min\{\infty,\,4+1\}=5 (next hop BB); per DD, min⁡{∞, 4+∞}=∞\min\{\infty,\,4+\infty\}=\infty (nessun miglioramento: BB non conosce ancora DD). Poi arriva il DV di FF (con dF,G=1d_{F,G}=1, dF,E=3d_{F,E}=3) e AA calcola, con DA,F=1D_{A,F}=1: per GG, min⁡{5, 1+1}=2\min\{5,\,1+1\}=2 (next hop FF); per EE, min⁡{∞, 1+3}=4\min\{\infty,\,1+3\}=4 (next hop FF).

Convergenza: giro per giro

Se tutti i nodi scambiano i DV in giri sincroni, il vettore di AA nella rete A,…,GA,\dots,G evolve così (ogni giro tutti i nodi usano i DV del giro precedente):

giro B C D E F G
0 (solo vicini) 4 ∞\infty ∞\infty ∞\infty 1 ∞\infty
1 4 6 ∞\infty 4 1 2
2 3 6 9 4 1 2
3 3 5 9 4 1 2
4 3 5 8 4 1 2
5 3 5 8 4 1 2

Il giro 5 non cambia più niente: l'algoritmo è a regime. Il giro kk ha trovato i cammini minimi con al più k+1k+1 archi; il cammino A→DA\to D ottimo (A ⁣− ⁣F ⁣− ⁣G ⁣− ⁣B ⁣− ⁣C ⁣− ⁣DA\!-\!F\!-\!G\!-\!B\!-\!C\!-\!D, costo 8) ha 5 archi, quindi serve il giro 4 (dimostrazione sotto). I risultati coincidono con Dijkstra (stessa tabella di AA). Le tabelle a regime (destinazione, distanza, next hop) per AA, BB e CC sono:

dest. AA: dist. / next hop BB: dist. / next hop CC: dist. / next hop
A 0 / - 3 / G 5 / B
B 3 / F 0 / - 2 / B
C 5 / F 2 / C 0 / -
D 8 / F 5 / C 3 / D
E 4 / F 5 / G 7 / B
F 1 / F 2 / G 4 / B
G 2 / F 1 / G 3 / B

Guasto di un collegamento

Se il collegamento B ⁣− ⁣GB\!-\!G si rompe: BB non riceve più HELLO da GG; scaduto il timeout BB toglie GG dai vicini e cancella dalla tabella tutte le righe che hanno GG come next hop, poi manda il nuovo DV ai suoi vicini (e GG fa lo stesso). L'aggiornamento si propaga e a regime le tabelle sono quelle dell'albero senza B ⁣− ⁣GB\!-\!G: ad esempio BB raggiunge GG con costo 2+4=62+4=6 passando per CC (B→C→GB\to C\to G) e AA raggiunge DD con costo 4+2+3=94+2+3=9 passando per BB. In generale, un nodo che rileva un guasto o una variazione di costo manda subito il proprio DV ai vicini e riavvia il processo distribuito.

Il problema del conteggio all'infinito

Nella rete senza B ⁣− ⁣GB\!-\!G si rompe anche il collegamento C ⁣− ⁣DC\!-\!D. Prima del guasto BB raggiunge DD con costo 55 passando per CC. Succede questo:

  1. CC cancella la riga verso DD ma, prima di mandare il suo DV, riceve il DV di BB che dice "raggiungo DD con 5". CC calcola 2+5=72+5=7 e aggiorna: DD a costo 7 con next hop BB.
  2. CC manda il DV a BB: BB vede che il percorso verso DD (già via CC) è cambiato e calcola 2+7=92+7=9.
  3. BB manda il DV a CC: CC calcola 2+9=112+9=11. E così via.

Costo di DD visto da CC e da BB: 7,9,11,13,15,17,…7, 9, 11, 13, 15, 17, \dots: cresce di 2 a ogni messaggio, cioè di 4 a ogni scambio completo (B→CB\to C e C→BC\to B), perché ogni nodo somma il costo 22 del collegamento B ⁣− ⁣CB\!-\!C alla stima del vicino (dopo kk messaggi la stima vale 5+2k5+2k). Cresce fino all'infinito, ma lentamente. Nel frattempo i pacchetti per DD rimbalzano tra BB e CC (problema del ciclo a due salti, two-hop loop), perché il percorso verso DD non esiste più.

Grafico interattivo: Conteggio all'infinito: stima del costo verso D dopo n messaggi

La stima supera la soglia 1616 al sesto messaggio (5+2⋅6=17>165+2\cdot6=17>16; il quinto dà 15<1615<16): lì il costo viene considerato infinito e il conteggio si ferma.

Soluzioni:

  • Infinito limitato (limited infinity): una distanza maggiore di 16 è considerata infinita. Funziona solo in reti con distanza massima tra due nodi inferiore a 16. Nell'esempio il conteggio si ferma quando si arriva a ≥16\ge16 (dopo pochi scambi: 7,9,11,13,15,17→16=∞7, 9, 11, 13, 15, 17\to16=\infty).
  • Hold down: quando un router viene informato che una destinazione non è raggiungibile ignora per 60 s ogni aggiornamento per quella destinazione, evitando che informazioni obsolete siano prese per valide (a prezzo di reagire più lentamente ai cambi di topologia).
  • Aggiornamento immediato (triggered update): i cambi di topologia sono notificati con priorità, senza aspettare il timer: convergenza più rapida e guasti scoperti prima.
  • Split horizon: a ciascun vicino YY si inviano solo le righe del DV che non hanno YY come next hop. Nell'esempio BB non manda a CC la riga di DD (perché BB raggiunge DD proprio attraverso CC): il ciclo non nasce.
  • Poison reverse: lo split horizon ha un difetto: se BB omette la riga di DD, CC non sa se è perché BB applica lo split horizon o perché non conosce davvero DD. Con il poison reverse il nodo manda tutte le destinazioni ma mette ∞\infty per quelle raggiungibili attraverso il collegamento su cui sta inviando: BB dice a CC "per DD il costo è +∞+\infty": "non usare questo valore, quello che so su questa strada viene da te".

Nota. Split horizon e poison reverse eliminano i cicli a due salti ma non tutti i cicli (con tre o più nodi in cerchio il conteggio all'infinito può ancora presentarsi): per questo sono combinati con l'infinito limitato.

Path vector

I costi non permettono a chi invia di imporre politiche sul percorso del pacchetto: con il percorso di costo minimo la strada la decide la metrica. Nel path vector il percorso migliore è scelto dalla sorgente in base alla politica che le interessa, quindi la sorgente può controllare la strada. L'obiettivo non è minimizzare un costo ma la raggiungibilità: far arrivare il pacchetto a destinazione in modo conveniente, senza assegnare costi ai cammini.

L'albero che ne esce è un albero di copertura (spanning tree) ma non è l'albero di costo minimo: è quello determinato dalla politica della sorgente. Una sorgente può applicare più politiche insieme, per esempio "usa il minor numero di nodi" (simile al costo minimo) oppure "evita certi nodi come nodi intermedi". Come il distance vector, l'algoritmo è asincrono e distribuito:

  1. un nodo all'avvio crea un vettore dei cammini con le informazioni sui vicini immediati (invia messaggi di saluto, HELLO + ECHO, per raccoglierle);
  2. lo manda a tutti i vicini;
  3. quando riceve il vettore di un vicino vv lo combina col proprio con una regola simile a Bellman-Ford, ma applicando la propria politica invece del costo minimo: Path(x,y)=best{ Path(x,y), x+Path(v,y) },∀v≠x,\text{Path}(x,y)=\text{best}\{\,\text{Path}(x,y),\ x+\text{Path}(v,y)\,\},\qquad \forall v\ne x, dove x+Path(v,y)x+\text{Path}(v,y) è il cammino ottenuto anteponendo xx al cammino annunciato da vv verso yy.

Rilevamento dei cicli. Ogni annuncio contiene l'intero cammino. Un nodo che riceve un cammino in cui compare già sé stesso lo scarta: i cammini sono privi di cicli e il problema del conteggio all'infinito non esiste (è quanto fa BGP, con i numeri di AS al posto dei router).

Esempio. Rete con archi A ⁣− ⁣BA\!-\!B, B ⁣− ⁣CB\!-\!C, A ⁣− ⁣DA\!-\!D, D ⁣− ⁣CD\!-\!C, C ⁣− ⁣EC\!-\!E e destinazione EE. AA riceve da BB l'annuncio "per EE: B C EB\,C\,E" e da DD l'annuncio "per EE: D C ED\,C\,E". Con la politica "non attraversare DD" AA sceglie A B C EA\,B\,C\,E anche se, per costi dei collegamenti, passare da DD fosse più economico. Se invece CC riannunciasse a BB un cammino che contiene BB, BB lo scarta.

L'esito di un algoritmo di instradamento è una tabella di instradamento (routing table), con (1) l'indirizzo della rete di destinazione, (2) il router a cui inoltrare il pacchetto (next hop), (3) il costo per raggiungere la destinazione; il formato dei pacchetti scambiati è fissato dal protocollo di instradamento. Come si usa la tabella è in Instradamento e inoltroL'inoltro (forwarding) mette il pacchetto sulla strada verso la destinazione, un salto alla volta (hop by hop). Se la destinazione è nella stessa rete del mittente l'inoltro è diretto (si usa l'ARP per il MAC del destinatario), altrimenti è indiretto: il pacchetto va al router successivo (next hop) indicato dalla tabella di instradamento, o al default gateway. Con le netmask: l'inoltro è diretto attraverso l'interfaccia $x$ se $\text{IP(dst)}\ \text{AND}\ \text{NM}(x)=\text{IP}(x)\ \text{AND}\ \text{NM}(x)$; altrimenti si scorre la tabella dalla maschera più lunga (longest prefix match) e si usa il primo match. La riga con rete $0.0.0.0$ e maschera $0.0.0.0$ (default route) corrisponde sempre. L'aggregazione di rotte (route aggregation) riduce la tabella, e nell'inoltro con etichette (MPLS) la tabella si consulta per indice.Instradamento e inoltro →.

Dimostrazioni di correttezza

Notazione: δ(s,v)\delta(s,v) è il costo minimo (vero) da ss a vv; c(u,v)≥0c(u,v)\ge0 il costo dell'arco.

Proprietà (sottostruttura ottima). Se s=v0,v1,…,vk=vs=v_0,v_1,\dots,v_k=v è un cammino minimo da ss a vv, ogni suo tratto vi,…,vjv_i,\dots,v_j è un cammino minimo da viv_i a vjv_j. Di conseguenza δ(s,v)=min⁡u{δ(s,u)+c(u,v)}\delta(s,v)=\min_{u}\{\delta(s,u)+c(u,v)\} al variare dei vicini uu di vv (equazione di Bellman).

Dimostrazione. Se per assurdo il tratto vi→vjv_i\to v_j avesse un'alternativa di costo minore, sostituendola si otterrebbe un cammino s→vs\to v di costo minore di δ(s,v)\delta(s,v): assurdo. L'equazione di Bellman segue perché l'ultimo arco di un cammino minimo è (u,v)(u,v) per qualche vicino uu e il tratto s→us\to u è minimo. □\square

Correttezza di Dijkstra (costi non negativi)

Proprietà (invariante di Dijkstra). Quando un nodo uu diventa permanente, du=δ(s,u)d_u=\delta(s,u). Inoltre per ogni nodo vv non permanente dvd_v è la lunghezza del cammino minimo da ss a vv che usa come nodi intermedi soli nodi permanenti.

Dimostrazione per induzione sull'ordine con cui i nodi diventano permanenti.

  • Base. Il primo nodo permanente è ss con ds=0=δ(s,s)d_s=0=\delta(s,s) (i costi sono ≥0\ge0, nessun cammino può costare meno).
  • Passo. Sia PP l'insieme dei nodi permanenti e valga l'invariante per tutti i nodi in PP. Sia u∉Pu\notin P il nodo con dud_u minima tra i temporanei: l'algoritmo lo rende permanente. Supponiamo per assurdo che esista un cammino Π\Pi da ss a uu di costo <du<d_u. Poiché s∈Ps\in P e u∉Pu\notin P, Π\Pi esce da PP: sia (x,y)(x,y) il primo arco con x∈Px\in P, y∉Py\notin P (può essere y=uy=u). Quando xx è diventato permanente l'algoritmo ha rilassato (x,y)(x,y), quindi dy  ≤  dx+c(x,y)  =  δ(s,x)+c(x,y)  ≤  costo del tratto di Π da s a y  ≤  costo(Π)  <  du.d_y\;\le\;d_x+c(x,y)\;=\;\delta(s,x)+c(x,y)\;\le\;\text{costo del tratto di }\Pi\text{ da }s\text{ a }y\;\le\;\text{costo}(\Pi)\;<\;d_u . Il primo passaggio è il rilassamento dell'arco (x,y)(x,y); l'uguaglianza è l'ipotesi induttiva su x∈Px\in P; il terzo passaggio dice che il tratto di Π\Pi fino a xx costa almeno δ(s,x)\delta(s,x) (per definizione di costo minimo); l'ultimo usa c≥0c\ge0: il resto di Π\Pi da yy a uu non può avere costo negativo. Ma allora yy è temporaneo con dy<dud_y<d_u, contro la scelta di uu come minimo. Quindi nessun cammino costa meno di dud_u e du=δ(s,u)d_u=\delta(s,u).
  • Seconda parte. Rendere permanente uu e rilassare i suoi archi mantiene l'invariante, perché i nuovi cammini candidati sono quelli che passano per uu come ultimo nodo permanente. □\square

Dove serve c≥0c\ge0. Con un costo negativo il passaggio "il resto di Π\Pi non costa meno di zero" cade. Controesempio: archi s ⁣→ ⁣as\!\to\! a di costo 2, s ⁣→ ⁣bs\!\to\! b di costo 3, b ⁣→ ⁣ab\!\to\! a di costo −2-2. Dijkstra rende permanente aa con da=2d_a=2 (minimo tra 2 e 3), ma il cammino s→b→as\to b\to a costa 1<21<2. In una rete di router i costi sono sempre positivi (ritardi, numeri di salti), quindi Dijkstra si può usare.

Correttezza di Bellman-Ford (e del distance vector)

Sia Dk(A,w)D^{k}(A,w) la stima di AA per ww dopo kk giri sincroni, con D0(A,w)=c(A,w)D^{0}(A,w)=c(A,w) se AA e ww sono vicini, 00 se A=wA=w, ∞\infty altrimenti. Il giro k+1k+1 applica la regola dell'algoritmo: Dk+1(A,w)=min⁡{Dk(A,w), min⁡Y vicino di A(c(A,Y)+Dk(Y,w))}.D^{k+1}(A,w)=\min\Big\{D^{k}(A,w),\ \min_{Y\ \text{vicino di }A}\big(c(A,Y)+D^{k}(Y,w)\big)\Big\}.

Proprietà (invariante di Bellman-Ford). Dk(A,w)D^{k}(A,w) è il costo minimo tra i cammini da AA a ww con al più k+1k+1 archi.

Dimostrazione per induzione su kk.

  • Base (k=0k=0). I cammini con al più un arco sono il cammino vuoto (A=wA=w) e i collegamenti diretti: è esattamente D0D^0.
  • Passo. Un cammino da AA a ww con al più k+2k+2 archi o ha al più k+1k+1 archi (e il minimo di questi è Dk(A,w)D^{k}(A,w) per ipotesi), oppure ha esattamente k+2k+2 archi: il primo è (A,Y)(A,Y) per un vicino YY, e il resto è un cammino da YY a ww con k+1k+1 archi, quindi il minimo è c(A,Y)+Dk(Y,w)c(A,Y)+D^{k}(Y,w). Il minimo tra tutte queste alternative è Dk+1(A,w)D^{k+1}(A,w). □\square

Conseguenza (convergenza). Se la rete non ha cicli di costo negativo (e con costi ≥0\ge0 non ne ha), un cammino minimo è semplice, cioè non ripete nodi, e ha quindi al più n−1n-1 archi. Dopo n−2n-2 giri (in pratica n−1n-1) tutte le stime sono i veri costi minimi e un ulteriore giro non cambia niente: è la condizione di regime vista nella tabella dei giri. Nell'esempio, il cammino minimo A→DA\to D ha 5 archi, quindi D4(A,D)=8D^{4}(A,D)=8 è il primo valore esatto: lo conferma la tabella dei giri.

Versione asincrona. Nella rete vera i DV non sono scambiati a giri sincroni, ma vale lo stesso: (1) le stime non scendono mai sotto il valore vero, perché ogni stima è il costo di un cammino realmente esistente; (2) per induzione sul numero di archi del cammino minimo, quando AA riceve i DV già esatti dei vicini la sua stima diventa esatta e resta tale. Dopo al più n−1n-1 periodi di aggiornamento senza altri cambiamenti di topologia le stime sono esatte.

Perché allora il conteggio all'infinito? La prima proprietà ("ogni stima è il costo di un cammino realmente esistente") vale solo se la topologia non cambia. Se un collegamento si rompe, alcune stime descrivono cammini che non esistono più: sono più basse del vero costo (che ora è ∞\infty o più alto) e continuano a circolare tra i nodi, come nel ciclo B↔CB\leftrightarrow C dell'esempio, finché il costo non cresce abbastanza. Per questo servono i rimedi della sezione precedente. Dijkstra, che lavora su una fotografia completa del grafo, non ha questo problema.

Versione ripasso

Il problema

Metriche

criterio costo ci,jc_{i,j}
minimo numero di salti 11
minimo ritardo end-to-end Li,j/Ri,j+tp(i,j)L_{i,j}/R_{i,j}+t_p(i,j)
minima probabilità di perdita −log⁡Pok(i,j)-\log P_{ok}(i,j)
massimo throughput 1/Ri,j n1/R_{i,j}^{\,n}, n>1n>1 intero
  • Ritardo: L=12 000L=12\,000 bit, R=10R=10 Mbit/s, tp=2t_p=2 ms ⇒c=1,2+2=3,2\Rightarrow c=1{,}2+2=3{,}2 ms.
  • Perdite: Pok=0,9P_{ok}=0{,}9 e 0,80{,}8: successo 0,720{,}72; −ln⁡0,9−ln⁡0,8=0,1054+0,2231=0,3285=−ln⁡0,72-\ln0{,}9-\ln0{,}8=0{,}1054+0{,}2231=0{,}3285=-\ln0{,}72 (minimizzare la somma = massimizzare il successo).
  • Throughput = minimo dei bitrate (collo di bottiglia), non una somma: non è additivo, si approssima con nn grande. Es. PP: 10 collegamenti da 100; QQ: 50 e 100. n=1n=1: P=0,1P=0{,}1, Q=0,03Q=0{,}03 (vince QQ, sbagliato); n=6n=6: P=10−11P=10^{-11}, Q=6,5⋅10−11Q=6{,}5\cdot10^{-11} (vince PP, giusto).
  • Statico (tabelle a mano, reti piccole, nessuna reazione ai guasti) contro dinamico (il protocollo aggiorna le tabelle; traffico di controllo e tabelle incoerenti nei transitori).
link state distance vector path vector
algoritmo Dijkstra Bellman-Ford spanning tree con politica
informazione topologia completa solo vicini solo vicini
si scambia i propri collegamenti con tutti distanze verso tutti con i vicini cammini interi con i vicini
obiettivo costo minimo costo minimo raggiungibilità per politica
protocolli OSPF, IS-IS RIP, IGRP BGP
  • HELLO (identifica i vicini), ECHO (misura il costo locale), poi il Link State Packet (sorgente + coppie vicino-costo) diffuso con flooding a tutti, da ripetere a ogni cambio di stato. Con tutti gli LSP ogni router ha il grafo e applica Dijkstra.
  • Esempio A,…,GA,\dots,G (archi A ⁣− ⁣B=4A\!-\!B=4, A ⁣− ⁣F=1A\!-\!F=1, B ⁣− ⁣C=2B\!-\!C=2, B ⁣− ⁣G=1B\!-\!G=1, C ⁣− ⁣D=3C\!-\!D=3, C ⁣− ⁣G=4C\!-\!G=4, D ⁣− ⁣E=6D\!-\!E=6, E ⁣− ⁣F=3E\!-\!F=3, F ⁣− ⁣G=1F\!-\!G=1): LSP di AA = (B 4, F 1).

Dijkstra (one-to-all)

  • Stato di ogni nodo (dℓ, p/t)(d_\ell,\ p/t): stima della distanza e etichetta permanente (distanza minima già nota) o temporanea.
  1. ss ha (0,p)(0,p) ed è il nodo corrente, gli altri (∞,t)(\infty,t).
  2. Rilassamento per ogni vicino vv non permanente del corrente uu: dv=min⁡{dv, du+cu,v}d_v=\min\{d_v,\ d_u+c_{u,v}\}; se vince il secondo termine si aggiorna il predecessore di vv.
  3. Diventa permanente (e corrente) il temporaneo con dd minima; si ripete finché ci sono nodi temporanei raggiungibili.
  4. Il cammino si legge seguendo i predecessori da vv a ss e invertendo.
  • Complessità: scorrendo l'elenco O(n2)O(n^2); con coda con priorità O((n+m)log⁡n)O((n+m)\log n).
  • Esempio 1 (sorgente 1; 1 ⁣− ⁣2=71\!-\!2=7, 1 ⁣− ⁣3=91\!-\!3=9, 1 ⁣− ⁣6=141\!-\!6=14, 2 ⁣− ⁣3=102\!-\!3=10, 2 ⁣− ⁣4=152\!-\!4=15, 3 ⁣− ⁣4=113\!-\!4=11, 3 ⁣− ⁣6=23\!-\!6=2, 4 ⁣− ⁣5=64\!-\!5=6, 5 ⁣− ⁣6=95\!-\!6=9): si fissano 1 (00), 2 (77), 3 (99), 6 (min⁡{14, 9+2}=11\min\{14,\,9+2\}=11), poi 5 (11+9=2011+9=20) e 4 (min⁡{22, 9+11}=20\min\{22,\,9+11\}=20, pari merito con 5). Distanze d2=7d_2=7, d3=9d_3=9, d6=11d_6=11, d4=20d_4=20, d5=20d_5=20. Cammino 1→3→6→51\to3\to6\to5 (costo 9+2+9=209+2+9=20) e 1→3→41\to3\to4 (9+11=209+11=20).
  • Esempio 2 (sorgente AA), ordine di fissaggio A,F,G,B,E,C,DA,F,G,B,E,C,D:
passo permanenti B C D E F G
0 AA 4-A ∞\infty ∞\infty ∞\infty 1-A ∞\infty
1 +F+F 4-A ∞\infty ∞\infty 4-F 1-A 2-F
2 +G+G 3-G 6-G ∞\infty 4-F 2-F
3 +B+B 3-G 5-B ∞\infty 4-F
4 +E+E 5-B 10-E 4-F
5 +C+C 5-B 8-C
6 +D+D 8-C
  • Passi chiave: da GG, B=2+1=3<4B=2+1=3<4; da BB, C=3+2=5<6C=3+2=5<6; da CC, D=5+3=8<10D=5+3=8<10.
  • Albero di AA: A ⁣− ⁣FA\!-\!F, F ⁣− ⁣GF\!-\!G, G ⁣− ⁣BG\!-\!B, B ⁣− ⁣CB\!-\!C, C ⁣− ⁣DC\!-\!D, F ⁣− ⁣EF\!-\!E. Tabella di AA (tutto con next hop FF): B3B3, C5C5, D8D8, E4E4, F1F1, G2G2. Ogni router esegue Dijkstra da sé, con sé stesso come sorgente.

Distance vector

  • Nessuno conosce la topologia: ogni nodo parte dai vicini (HELLO/ECHO) e costruisce il vettore delle distanze (distanza e next hop per ogni destinazione). DV iniziale di AA: B=4B=4 via BB, F=1F=1 via FF, il resto ∞\infty.
  • I DV si mandano ai vicini a intervalli casuali tra 25 e 35 s o quando cambiano. Riga non aggiornata entro 180 s (expiration): costo ∞\infty; cancellata dopo altri 120 s (garbage collection).

Bellman-Ford: DA,w=min⁡{ DA,w, DA,Y+dY,w }D_{A,w}=\min\{\,D_{A,w},\ D_{A,Y}+d_{Y,w}\,\}, con DA,YD_{A,Y} costo del collegamento A→YA\to Y e dY,wd_{Y,w} costo stimato da YY a ww; se vince il secondo termine, next hop =Y=Y.

  • Esempio: AA riceve il DV di BB (DA,B=4D_{A,B}=4; dB,C=2d_{B,C}=2, dB,G=1d_{B,G}=1): C=min⁡{∞,4+2}=6C=\min\{\infty,4+2\}=6, G=min⁡{∞,4+1}=5G=\min\{\infty,4+1\}=5, DD resta ∞\infty (BB non lo conosce). Poi da FF (DA,F=1D_{A,F}=1; dF,G=1d_{F,G}=1, dF,E=3d_{F,E}=3): G=min⁡{5,1+1}=2G=\min\{5,1+1\}=2, E=1+3=4E=1+3=4.
  • Convergenza a giri sincroni (vettore di AA):
giro B C D E F G
0 4 ∞\infty ∞\infty ∞\infty 1 ∞\infty
1 4 6 ∞\infty 4 1 2
2 3 6 9 4 1 2
3 3 5 9 4 1 2
4 3 5 8 4 1 2
  • Il giro 5 non cambia niente: regime, uguale a Dijkstra. Il giro kk trova i cammini con al più k+1k+1 archi; A→DA\to D ottimo (A ⁣− ⁣F ⁣− ⁣G ⁣− ⁣B ⁣− ⁣C ⁣− ⁣DA\!-\!F\!-\!G\!-\!B\!-\!C\!-\!D, costo 8) ha 5 archi, quindi serve il giro 4.
  • A regime BB: A3A3 via GG, C2C2 via CC, D5D5 via CC, E5E5 via GG, F2F2 via GG, G1G1 via GG.

Guasti e conteggio all'infinito

  • Guasto B ⁣− ⁣GB\!-\!G: BB non riceve più HELLO, toglie GG dai vicini, cancella le righe con next hop GG, manda il nuovo DV. A regime BB raggiunge GG con 2+4=62+4=6 via CC e AA raggiunge DD con 4+2+3=94+2+3=9 via BB.
  • Con rotto anche C ⁣− ⁣DC\!-\!D (BB raggiungeva DD con 5 via CC): CC riceve il DV di BB ("DD a 5") e calcola 2+5=72+5=7 via BB; BB calcola 2+7=92+7=9; CC calcola 2+9=112+9=11... il costo cresce di 4 a ogni scambio completo (7,9,11,13,15,17,…7,9,11,13,15,17,\dots) e i pacchetti rimbalzano tra BB e CC (ciclo a due salti).
  • Rimedi:
    • infinito limitato: distanza oltre 16 = infinito (funziona se la distanza massima tra due nodi è inferiore a 16; qui 7,…,15,17→16=∞7,\dots,15,17\to16=\infty);
    • hold down: 60 s in cui si ignorano gli aggiornamenti su una destinazione appena data per irraggiungibile (costo: reazione più lenta ai cambi);
    • aggiornamento immediato (triggered update): i cambi di topologia sono notificati subito;
    • split horizon: a YY non si mandano le righe che hanno YY come next hop (BB non manda a CC la riga di DD);
    • poison reverse: si mandano tutte le righe ma con ∞\infty per quelle raggiungibili attraverso il collegamento su cui si invia (così CC distingue "non conosco DD" da "lo raggiungo da te").
  • Split horizon e poison reverse tolgono i cicli a due salti ma non tutti (con tre o più nodi il conteggio può tornare): si combinano con l'infinito limitato.
distance vector link state
RIP, Bellman-Ford OSPF, Dijkstra
manda (una copia di) tutta la tabella manda solo gli aggiornamenti dei collegamenti
non richiede la topologia richiede la topologia
aggiornamenti frequenti, convergenza lenta aggiornamenti legati agli eventi, convergenza rapida

Path vector

  • Il costo non permette alla sorgente di imporre politiche: nel path vector il cammino lo sceglie la sorgente secondo la sua politica (es. "meno nodi possibile", "evita certi nodi intermedi"). Scopo: raggiungibilità, senza costi; l'albero è di copertura ma non di costo minimo.
  • Asincrono e distribuito: vettore iniziale dai vicini (HELLO + ECHO), invio ai vicini, combinazione con Path(x,y)=best{Path(x,y), x+Path(v,y)}\text{Path}(x,y)=\text{best}\{\text{Path}(x,y),\ x+\text{Path}(v,y)\}, ∀v≠x\forall v\ne x.
  • Cicli: l'annuncio contiene l'intero cammino; se compare già il nodo stesso, lo scarta. Niente conteggio all'infinito (BGP, con i numeri di AS).
  • Esempio: archi A ⁣− ⁣BA\!-\!B, B ⁣− ⁣CB\!-\!C, A ⁣− ⁣DA\!-\!D, D ⁣− ⁣CD\!-\!C, C ⁣− ⁣EC\!-\!E, destinazione EE; AA riceve "B C EB\,C\,E" e "D C ED\,C\,E"; con la politica "non attraversare DD" sceglie A B C EA\,B\,C\,E.

Correttezza

  • Sottostruttura ottima: ogni tratto di un cammino minimo è minimo (se no, sostituendolo si migliorerebbe il totale). Equazione di Bellman: δ(s,v)=min⁡u{δ(s,u)+c(u,v)}\delta(s,v)=\min_u\{\delta(s,u)+c(u,v)\} sui vicini uu di vv.
  • Dijkstra (c≥0c\ge0): quando uu diventa permanente du=δ(s,u)d_u=\delta(s,u). Induzione: se esistesse un cammino Π\Pi di costo <du<d_u, esce dai permanenti da un primo arco (x,y)(x,y), e dy≤dx+c(x,y)=δ(s,x)+c(x,y)≤costo(Π)<du,d_y\le d_x+c(x,y)=\delta(s,x)+c(x,y)\le\text{costo}(\Pi)<d_u, cioè rilassamento, ipotesi induttiva, minimalità di δ\delta e c≥0c\ge0; ma allora yy (temporaneo) avrebbe dy<dud_y<d_u, contro la scelta di uu. Con costi negativi cade: s→a=2s\to a=2, s→b=3s\to b=3, b→a=−2b\to a=-2 dà da=2d_a=2 ma s→b→as\to b\to a costa 11.
  • Bellman-Ford: Dk+1(A,w)=min⁡{Dk(A,w), min⁡Y(c(A,Y)+Dk(Y,w))}D^{k+1}(A,w)=\min\{D^k(A,w),\ \min_Y(c(A,Y)+D^k(Y,w))\}, e Dk(A,w)D^k(A,w) è il minimo sui cammini con al più k+1k+1 archi (induzione sul primo arco (A,Y)(A,Y)). Senza cicli negativi un cammino minimo è semplice, ha al più n−1n-1 archi: convergenza dopo n−1n-1 giri. Nell'esempio D4(A,D)=8D^4(A,D)=8 è il primo valore esatto.
  • Versione asincrona: le stime non scendono sotto il vero (sono costi di cammini esistenti) e diventano esatte in al più n−1n-1 periodi. Dopo un guasto alcune stime descrivono cammini che non esistono più: da qui il conteggio all'infinito, che Dijkstra (grafo completo) non ha.
  • Errori tipici: dimenticare il +1+1 di kk (giro kk = k+1k+1 archi), scambiare le etichette sugli archi dell'albero (distanze da AA) per costi, usare Dijkstra con costi negativi, scambiare split horizon (omette la riga) con poison reverse (la manda a ∞\infty).

Lezioni in cui compare

Teoria collegata