Modulo Neighborhood - Dettagli Tecnici

Requisiti

L'utilizzatore del modulo Neighborhood per prima cosa inizializza il modulo richiamando il metodo statico init di NeighborhoodManager. In tale metodo viene anche passata l'istanza di INtkdTasklet per fornire l'implementazione del sistema di tasklet.

Dopo istanzia il suo NeighborhoodManager passando al costruttore:

Dopo, per ogni interfaccia di rete che intende gestire, richiama sul NeighborhoodManager il metodo start_monitor ( INeighborhoodNetworkInterface nic ) .

Deliverables

Il modulo segnala la collisione con un altra rete attraverso il segnale network_collision di NeighborhoodManager.


Il modulo segnala la costituzione di un arco attraverso il segnale arc_added di NeighborhoodManager.


Il modulo segnala la rimozione di un arco attraverso il segnale arc_removed di NeighborhoodManager.


Il modulo segnala la variazione del costo di un arco attraverso il segnale arc_changed di NeighborhoodManager.


Il modulo permette di ottenere l'elenco degli archi ora presenti con il metodo current_arcs di NeighborhoodManager.


Il modulo permette di stabilire se un messaggio unicast ricevuto sia da processare con il metodo is_unicast_for_me di NeighborhoodManager.


Il modulo permette di stabilire se un messaggio broadcast ricevuto sia da processare con il metodo is_broadcast_for_me di NeighborhoodManager.


Il modulo permette di ottenere uno stub per inviare un messaggio reliable ad un vicino tramite un arco con il metodo get_stub_tcp di NeighborhoodManager.


Il modulo permette di ottenere uno stub per inviare un messaggio in broadcast con i metodi get_stub_broadcast e get_stub_broadcast_to_dev di NeighborhoodManager.


Il modulo permette di forzare la rimozione di un arco con il metodo remove_my_arc di NeighborhoodManager.

Rilevamento dei vicini, costituzione degli archi, misurazione dei costi

Quando viene chiamato il metodo start_monitor, il modulo inizia a gestire una interfaccia di rete. Di essa riceve il nome e il MAC address. Per prima cosa verifica che questi valori siano univoci. Cicla le interfacce che ha già in gestione; se una ha gli stessi valori per nome e MAC allora ignora questa richiesta che è un duplicato; se una ha lo stesso MAC e nome diverso oppure lo stesso nome e MAC diverso allora il modulo va in errore fatale.

Il modulo, per ogni interfaccia che inizia a gestire, memorizza il suo nome e il suo MAC address e genera e memorizza un indirizzo locale di scheda. Usa l'oggetto INeighborhoodIPRouteManager per impostare l'indirizzo generato.

Poi avvia una tasklet nella quale invia un broadcast_to_nic (cioè un broadcast solo su quella interfaccia di rete) con il messaggio "ci sono io" indicando il suo identificativo, il MAC della interfaccia e il suo indirizzo locale di scheda. Poi ripete lo stesso messaggio con bassa frequenza, ogni minuto.

I nodi che sono nel dominio di collisione vedono questo messaggio e possono fin da subito accordarsi per un arco. Quelli che hanno già costituito un arco verso quel MAC address ignorano il nuovo messaggio.

Un nodo che vuole accordarsi per un arco con un vicino di cui ha notato la presenza gli invia un unicast "facciamo un arco", indicando anche esso il suo identificativo e il MAC e l'indirizzo locale della interfaccia di rete, e riceverà la risposta. Dopo entrambi i nodi avranno un arco il cui costo è ancora non misurato.

Dopo essersi accordati per l'arco entrambi i nodi usano l'oggetto INeighborhoodIPRouteManager per impostare la rotta verso l'indirizzo di scheda del nuovo vicino. Quindi da subito è possibile realizzare connessioni reliable (con protocollo TCP) tra i due nodi passanti per questo nuovo arco.

Un arco il cui costo non è ancora stato misurato non va a far parte della lista ufficiale che il modulo neighborhood espone all'applicazione.

Dopo aver realizzato l'arco entrambi i nodi avviano una tasklet che si occuperà della monitorazione dell'arco e della misurazione del costo ad esso associato. In questa tasklet viene realizzata subito una prima misurazione e in seguito ogni 30 secondi si ripete. Nell'effettuare la misurazione si verifica anche il funzionamento stesso dell'arco e se non funziona viene rimosso.

La misurazione del costo espresso come RTT avviene attraverso l'uso concertato, da parte dei due nodi, dell'oggetto INeighborhoodNetworkInterface, come indicato nel relativo documento.

Per quanto riguarda la memorizzazione del costo, dopo aver rilevato la prima misurazione l'algoritmo è il seguente:

. costo_nuovo = <costo appena rilevato>
. costo_memorizzato = costo_nuovo
. costo_ufficiale = costo_memorizzato

Dopo ogni successiva misurazione l'algoritmo è il seguente:

. costo_nuovo = <costo appena rilevato>
. costo_delta = costo_nuovo - costo_memorizzato
. se (costo_delta > 0) costo_delta = costo_delta / 10
. se (costo_delta < 0) costo_delta = costo_delta / 3
. costo_memorizzato = costo_memorizzato + costo_delta
. se (costo_memorizzato < costo_ufficiale*0.5 OR costo_memorizzato > costo_ufficiale*2)
    . costo_ufficiale = costo_memorizzato

Questo algoritmo fa in modo che lievi variazioni non scatenino pesanti aggiornamenti e traffico di rete. Inoltre tiene conto della seguente osservazione: se ci sono misurazioni ravvicinate della latenza che differiscono quella più bassa è quella più vicina alla latenza puramente dovuta alla distanza dei due nodi, mentre quella più alta è stata probabilmente maggiormente influenzata dal carico del nodo o dal bufferbloat. Nonostante questa osservazione l'algoritmo pian piano si adegua se le misurazioni si mantengono su un valore elevato.

Produzione di uno stub per inviare un messaggio in broadcast

Il modulo Neighborhood riceve dal suo utilizzatore (nel costruttore di NeighborhoodManager) un'istanza di un oggetto di cui conosce l'interfaccia INeighborhoodStubFactory. Questa ha il metodo i_neighborhood_get_broadcast che restituisce un oggetto stub che effettua chiamate broadcast, dati questi parametri:

Un BroadcastID può contenere l'identificativo di un vicino da escludere dai destinatari (ignore_nodeid). Qualunque nodo che riceve il messaggio, se il proprio identificativo non equivale a ignore_nodeid, si considera destinatario del messaggio.

Quando il modulo neighborhood (NeighborhoodManager) vuole inviare un messaggio in broadcast:

Se si è passata comm, l'istanza di ModRpc.IAckCommunicator opzionale, allora la chiamata del metodo remoto deve seguire immediatamente la creazione dello stub, perché la tasklet (gestita da ZCD) che si metterà in attesa delle risposte ACK parte subito; dopo il timeout la lista responding_macs degli acknoledgements ricevuti sarà passata sul suo metodo process_macs_list e per gli archi mancanti verrà chiamato il metodo missing.


Il modulo può aver bisogno internamente di comunicare con i suoi vicini e per questo di produrre uno stub. Oppure lo stub gli può essere richiesto dall'esterno. In entrambi i casi questo algoritmo sopra delineato viene usato.

Produzione di uno stub per inviare un messaggio UDP in unicast

Con il termine 'messaggio in unicast' intendiamo un messaggio tramite protocollo UDP dove sono specificati il destinatario, l'interfaccia di rete del mittente, l'interfaccia di rete del destinatario.

L'interfaccia INeighborhoodStubFactory permette al modulo di ottenere uno stub per inviare un messaggio UDP (non reliable) ad un particolare vicino tramite una sua particolare interfaccia di rete, dati questi parametri:

Un UnicastID contiene l'identificativo del nodo destinatario e il MAC address dell'interfaccia di rete del nodo destinatario. Solo il nodo il cui identificativo corrisponde, quando riceve il messaggio attraverso l'interfaccia di rete il cui MAC address corrisponde, si considera destinatario di questo messaggio.

Chiamando un metodo su questo stub viene inviato un messaggio con il protocollo UDP sull'interfaccia di rete specificata, con un destinatario specifico. Il protocollo usato non è reliable. Se la comunicazione avviene correttamente il metodo chiamato viene eseguito sul nodo destinatario. Al momento della produzione dello stub il modulo può specificare se si intende attendere l'esecuzione del metodo nel nodo vicino oppure no. Se sì il risultato viene restituito dallo stub al modulo nel nodo origine.


Il modulo può aver bisogno internamente di comunicare con un suo vicino prima di aver realizzato un arco; in questo caso produce questo tipo di stub. In seguito, quando vi è un arco tra due nodi vicini, il modulo userà solo comunicazioni con protocollo reliable per inviare messaggi ad uno specifico vicino.

Questa modalità non reliable non viene fornita all'esterno dal modulo.

Produzione di uno stub per inviare un messaggio reliable ad un vicino tramite un arco

L'interfaccia INeighborhoodStubFactory permette al modulo anche di ottenere uno stub per inviare un messaggio reliable ad un paricolare vicino tramite un particolare arco, dati questi parametri:

Chiamando un metodo su questo stub viene inviato un messaggio con il protocollo TCP, quindi reliable. Il metodo attende che il messaggio raggiunga il vicino, ma al momento della produzione dello stub si può specificare se si intende attendere l'esecuzione del metodo nel nodo vicino oppure no.


Il modulo può aver bisogno internamente di comunicare con un suo vicino passando per un arco; in questo caso produce questo tipo di stub. Oppure lo stub gli può essere richiesto dall'esterno.

Indirizzo IPv4 di scheda

La comunicazione tra due nodi collegati da un arco deve poter avvenire in modo reliable. Infatti se la comunicazione risulta impossibile si deve procedere alla rimozione dell'arco stesso. Per implementare la comunicazione reliable si può far uso del protocollo TCP, ma per questo occorre poter associare ad ogni vertice dell'arco un indirizzo IP fisso.

Si assegna subito un indirizzo "locale" distinto ad ogni scheda di rete del nodo e lo si mantiene sempre, anche quando il nodo fa l'ingresso in una nuova rete, o migra in un diverso g-nodo, ecc.

L'unico requisito da soddisfare è che tale indirizzo IPv4 sia univoco tra tutti i vicini. Lo scegliamo in modo random nella classe di indirizzi 169.254.0.0/16.

Il caso in cui due nodi vicini si scelgano lo stesso indirizzo è ignorabile.

Quando si aggiunge una interfaccia di rete da monitorare, il modulo genera un nuovo indirizzo IPv4 locale e lo aggiunge ai suoi indirizzi su questa interfaccia di rete. Per farlo usa l'oggetto passatogli che implementa l'interfaccia INeighborhoodIPRouteManager, precisamente con il metodo 'i_neighborhood_add_address'.

Quando si smette di gestire l'interfaccia, il modulo rimuove anche l'indirizzo locale dalla interfaccia, con il metodo 'i_neighborhood_remove_address'.

Quando un nodo gestisce una interfaccia di rete, nel messaggio broadcast_to_nic "ci sono io" comunica il suo indirizzo scelto per quella scheda.

Quando viene realizzato un arco ciascuno dei due nodi:

Alla rimozione di un arco il nodo:

Quando si vuole inviare un messaggio ad un vicino attraverso un determinato arco si può usare il TCP verso l'indirizzo di scheda del vicino memorizzato su questo arco, quindi si ha un collegamento reliable.