Modulo Neighborhood - Analisi Funzionale

Ruolo del modulo

Il ruolo fondamentale del modulo Neighborhood è il rilevamento dei collegamenti (detti archi) che si possono realizzare con altri nodi diretti vicini, la loro realizzazione e la misurazione del costo associato a tali archi.

Un arco associa una specifica interfaccia di rete del nodo corrente con una specifica interfaccia di rete di un altro nodo diretto vicino. Tecnicamente, con il termine diretto vicino si intende che le due interfacce di rete suddette sono collegate ad un comune dominio broadcast.

Come vedremo in seguito, non sono ammessi due archi che partendo da una stessa interfaccia di rete del nodo corrente colleghino a due distinte interfacce di rete di uno stesso nodo diretto vicino. Per questo ogni arco deve identificare univocamente non soltanto la specifica interfaccia di rete di un vicino, ma anche il nodo vicino come entità nel suo insieme.

L'identificativo di un nodo vicino è chiamato NeigborhoodNodeID. Esso è un concetto interno al modulo Neighborhood. Riassumendo, ogni arco associa una interfaccia di rete del nodo corrente ad una coppia composta dal NeigborhoodNodeID del vicino e dal MAC address della sua interfaccia.

Come diretta conseguenza del ruolo di realizzazione e mantenimento degli archi, al modulo Neighborhood è demandato anche il compito di permettere agli altri moduli la comunicazione tra nodi:

Operazioni di base

Il modulo fa uso delle tasklet, un sistema di multithreading cooperativo. Attraverso di esso esegue il monitoraggio delle schede di rete lasciando libero il chiamante di svolgere altri task.

Il modulo fa uso del framework ZCD, precisamente appoggiandosi alla libreria di livello intermedio ntkdrpc prodotta con questo framework per formalizzare i metodi remoti usati nel demone ntkd.

Quando si inizializza, il modulo produce l'identificativo NeigborhoodNodeID del proprio nodo.

Il modulo riceve subito l'elenco delle interfacce di rete che deve gestire. Ad ognuna associa un indirizzo locale detto indirizzo di scheda.

Rileva i nodi vicini raggiungibili attraverso una (o più) interfacce di rete e ne reperisce l'identificativo NeigborhoodNodeID + MAC. Si veda sotto la trattazione dell'argomento degli archi multipli con un unico nodo vicino: essi sono ammessi solo se diversi MAC del vicino sono rilevati da diverse interfacce di rete del nodo corrente. Per verificare questo vincolo è necessario identificare un nodo vicino come singola entità (con il NeigborhoodNodeID) e non basarsi soltanto sui distinti MAC address.

Con ogni vicino, poi, si accorda per la creazione (o meno) di un arco. L'accordo potrebbe non essere raggiunto perché uno dei due vertici ha già un numero di archi elevato. Se l'accordo viene raggiunto entrambi i nodi vengono anche a conoscenza dell' indirizzo di scheda del vicino.

Sia k un arco che il modulo nel nodo corrente a ha creato con un vicino b. La struttura dati che il modulo mantiene per l'arco k contiene:

Quando il modulo crea un nuovo arco, esso imposta le rotte nelle tabelle del kernel per rendere possibile la comunicazione via TCP con il vicino attraverso gli indirizzi di scheda.

Nel tempo, il modulo gestisce la costituzione di nuovi archi, la rimozione di archi, i cambiamenti del costo degli archi.

Caratteristiche degli archi

Quando si crea un arco esso esiste per entrambi i nodi.


Tra due nodi vicini ci possono essere più collegamenti. Ad esempio i nodi A e B possono avere entrambi una interfaccia di rete wireless e una ethernet ed essere collegati sia con un cavo (direttamente o per il tramite di un hub) sia con le interfacce wireless (in modalità ad-hoc o per il tramite di un access point). Oppure ancora, un nodo C con due interfacce di rete ethernet può essere collegato tramite due cavi ad un unico switch al quale è collegato anche il nodo D.

Ci chiediamo: in quali casi può essere utile che i due nodi tengano in considerazione più di un arco? Se i collegamenti sono su distinti domini di collisione, è utile considerarli in modo distinto, poiché le trasmissioni fatte su un collegamento non influenzano la capacità dell'altro collegamento. Ad esempio i nodi A e B possono sfruttare in parallelo i due collegamenti (uno via cavo e l'altro via etere). Consideriamo il caso del nodo C che ha le due interfacce ethernet C0 e C1 collegate tramite due cavi ad uno switch1. Supponiamo che il nodo D sia collegato allo stesso switch con un solo cavo collegato alla sua interfaccia D0. Supponiamo che sia in corso una trasmissione di dati da D0 a C0. Allora questa trasmissione influenza la capacità del collegamento tra D0 e C1; quindi non potremmo usare questi due collegamenti in parallelo in modo efficiente.

Supponiamo, invece, che il nodo D sia collegato allo stesso switch con due cavi collegati alle sue interfacce D0 e D1. Supponiamo che sia in corso una trasmissione di dati da D0 a C0. Allora questa trasmissione, per le caratteristiche di uno switch, non influenza la capacità del collegamento tra D1 e C1; quindi potremmo usare questi due collegamenti in parallelo in modo efficiente.

Si consideri inoltre che uno switch, pur realizzando distinti domini di collisione, forma un unico dominio broadcast; questo significa che il nodo C tramite la sua interfaccia C0 con un messaggio in broadcast rileva la presenza del nodo D anche attraverso la sua interfaccia D1. E la stessa cosa vale per la coppia D0 e C1. Però non ha senso considerare tutti questi 4 possibili archi: lo sfruttamento ottimale si ha con due archi, ad esempio D0-C0 e D1-C1, che possono essere usati per due trasmissioni in parallelo che non si disturbano a vicenda.

Per avvicinarci allo sfruttamento ottimale descritto sopra, implementiamo questa regola: il modulo consente la costituzione di un secondo arco tra i nodi A e B solo se le interfacce di rete di entrambi i nodi sono diverse da quelle su cui è realizzato il primo arco.


Il costo di un arco in una direzione (da A verso B​) può essere diverso dal costo nella direzione inversa. Cioè ogni vertice effettua una misurazione del costo dell'arco indipendente da quella fatta dall'altro vertice. Questo non è utile quando il costo rappresenta il round-trip time, ma può esserlo se rappresenta la larghezza di banda in uscita.


Quando un nodo rimuove un arco tenta di comunicarlo al vertice collegato perché faccia altrettanto.

Identità multiple in un nodo

Introduciamo il concetto di identità. In un singolo nodo possono in dati momenti sussistere diverse identità. La ragione di essere di queste identità sarà discussa in dettaglio nella trattazione del modulo QSPN, quando si parla di nodi virtuali.

Ogni identità di un nodo ha un suo identificativo. Questo identificativo è distinto dal NeigborhoodNodeID, il quale è un concetto interno al modulo Neighborhood. L'identificativo assegnato ad una identità di un nodo lo chiamiamo semplicemente NodeID.

Il NodeID assegnato a ogni identità è essenzialmente un intero di 32 bit scelto a caso, assumendo che sia univoco a livello dei domini di collisione in cui il nodo partecipa con le sue interfacce di rete. Questo dettaglio implementativo non è di pertinenza del modulo Neighborhood. Il modulo sa solo che il NodeID può essere usato come identificativo univoco che si riferisce ad una precisa identità all'interno di un preciso nodo.

Ogni nodo ha sempre una e una sola identità principale. L'identità principale del nodo non è sempre la stessa: il nodo può in un certo momento creare una nuova identità e farla diventare la sua principale. L'identità principale (i concetti espressi in questa frase verranno chiariti in seguito nel documento) è quella che gestisce le interfacce di rete reali del nodo nel network namespace default, ognuna con il suo indirizzo di scheda.

Il modulo Neighborhood non ha conoscenza diretta di quali siano le identità che vivono nel suo nodo in un dato momento.

Abbiamo visto che la presenza di identità multiple in un nodo è supportata dal framework ZCD. Con questo intendiamo evidenziare che è possibile realizzare uno stub che possa essere usato da una precisa identità del nodo a, indichiamola con a0, per chiamare un metodo remoto su una precisa identità del nodo b, indichiamola con b0.

Abbiamo detto inoltre che fra i ruoli del modulo Neighborhood c'è quello di permettere agli altri moduli dell'applicazione la comunicazione con altri nodi. Ora aggiungiamo che un particolare modulo può essere interessato a questo tipo di identificazione precisa della identità all'interno di un nodo. Un altro modulo, invece, potrebbe essere agnostico rispetto a queste identità, e voler semplicemente chiamare un metodo remoto su un particolare nodo. Chiamiamo il primo tipo un modulo consapevole di identità o modulo di identità o identity-aware. Il secondo tipo è un modulo di nodo o whole-node. Di norma in un modulo di identità c'è una classe di cui viene creata una specifica istanza per ogni identità che il nodo assume.

Il modulo Neighborhood, lato client, deve saper produrre uno stub per ogni esigenza. Inoltre, lato server, deve saper individuare un elenco (con zero, uno o più elementi) di root-dispatcher a partire dal discriminatore contenuto in un messaggio ricevuto (cioè dall'oggetto CallerInfo); questi dispatcher, se il modulo da chiamare è un modulo di identità, devono saper indirizzare ognuno una precisa istanza del modulo da chiamare. Ricordiamo che l'oggetto CallerInfo è fornito dalla libreria di livello intermedio del framework ZCD prodotta con "rpcdesign" e che contiene queste informazioni:

Nei casi in cui il modulo che vuole comunicare è di identità, il NodeID che identifica una identità di un nodo è una parte essenziale delle classi che si usano come ISourceID, IUnicastID e IBroadcastID nella produzione di stub per chiamare metodi remoti.

Facciamo un esempio di un modulo di identità (ad esempio QSPN) in cui una precisa identità del nodo a, indichiamola con a0, vuole chiamare un metodo remoto su una precisa identità del nodo diretto vicino b, indichiamola con b0, passando attraverso l'arco x. Il nodo a chiama un metodo di Neighborhood per produrre uno stub di tipo identity_aware_unicast. In questo metodo il nodo passa un INeighborhoodArc che identifica l'arco x (questo è l'oggetto fornito dal modulo Neighborhood al suo esterno per rappresentare uno specifico arco formato con un diretto vicino). In questo oggetto è identificata l'interfaccia di rete di a e il MAC address dell'interfaccia di rete di b. Inoltre in questo metodo il nodo passa il NodeID di a0 e questo sarà usato dal modulo Neighborhood per produrre un IdentityAwareSourceID. Infine in questo metodo il nodo passa il NodeID di b0 e questo sarà usato dal modulo Neighborhood per produrre un IdentityAwareUnicastID. Lo stub prodotto in questo modo trasmetterà su una sola interfaccia di rete, univocamente individuata dal INeighborhoodArc passato al metodo. Per il lato server vedremo sotto come il nodo b aveva istruito il suo modulo Neighborhood perché potesse gestire questo tipo di IUnicastID.

Nelle trasmissioni unicast è sempre individuato un solo arco tra a e b. Per le trasmissioni in TCP questo è scontato, nel senso che il nodo b riceve il messaggio una sola volta attraverso l'interfaccia di rete specifica di quell'arco. E le trasmissioni unicast fatte dai moduli di identità sono sempre in TCP, come vedremo in seguito.

In particolare, nelle trasmissioni identity_aware_unicast abbiamo aggiunto come informazioni le identità a0 e b0; grazie a queste il nodo ricevente b (non il modulo Neighborhood, bensì il suo utilizzatore) è in grado di identificare la specifica istanza del modulo di identità da coinvolgere e anche di sapere (grazie a delle associazioni che vedremo meglio sotto) se esiste quello specifico arco-identità così individuato.

Facciamo un altro esempio di un modulo di identità in cui una precisa identità del nodo a, indichiamola con a0, vuole chiamare un metodo remoto su un set di precise identità dei nodi diretti vicini, diciamo b0, b1, c0 e d0. Il nodo a chiama un metodo di Neighborhood per produrre uno stub di tipo identity_aware_broadcast. In questo metodo il nodo passa il NodeID di a0 e questo sarà usato dal modulo Neighborhood per produrre un IdentityAwareSourceID. Inoltre in questo metodo il nodo passa i vari NodeID di b0, b1, c0 e d0 e questi saranno usati dal modulo Neighborhood per produrre un IdentityAwareBroadcastID. Lo stub prodotto in questo modo trasmetterà su tutte le interfacce di rete gestite dal nodo a. Per il lato server vedremo sotto come i nodi, ad esempio b, c, d ed anche e, avevano istruito ognuno il suo modulo Neighborhood perché potesse gestire questo tipo di IBroadcastID.

Nelle trasmissioni broadcast non sono individuati specifici archi tra a e gli altri nodi. Infatti il messaggio è trasmesso su tutte le interfacce di a e contiene come IBroadcastID un oggetto che non individua gli specifici MAC address dei destinatari. Guardiamo cosa succede alla ricezione da parte di uno dei nodi, diciamo b. Il nodo b quando riceve il messaggio trasmesso dalla interfaccia eth0(a) del nodo a leggendolo dalla sua interfaccia eth0(b), se esiste l'arco eth0(a)-eth0(b), non può fare altro che esaminarlo. In particolare, nelle trasmissioni identity_aware_broadcast abbiamo aggiunto come informazioni le identità a0 e b0 e b1. Il nodo b se l'arco eth0(a)-eth0(b) è associato a un arco-identità a0-b0 deve processarlo su questo arco-identità. Allo stesso modo se l'arco eth0(a)-eth0(b) è associato anche su un arco-identità a0-b1 deve processarlo anche su questo arco-identità. Se i nodi a e b hanno più di un arco che li collega, questa cosa può ripetersi per diverse volte a seguito di un solo messaggio broadcast, ad esempio anche con wlan0(a) e wlan0(b).

Nei casi in cui il modulo che vuole comunicare è di nodo, il NeigborhoodNodeID costituisce la parte essenziale delle classi che si usano come ISourceID, IUnicastID e IBroadcastID nella produzione di stub per chiamare metodi remoti.

Facciamo un esempio di un modulo di nodo in cui un nodo a vuole chiamare un metodo remoto su un nodo diretto vicino b, passando attraverso l'arco x. Il nodo a chiama un metodo di Neighborhood per produrre uno stub di tipo whole_node_unicast. In questo metodo il nodo passa un INeighborhoodArc che identifica l'arco x in cui è identificata l'interfaccia di rete di a e il MAC address dell'interfaccia di rete di b. Il modulo Neighborhood usa il suo NeigborhoodNodeID per produrre un WholeNodeSourceID. Inoltre dal INeighborhoodArc x si può reperire il NeighborhoodNodeID di b; questo sarà usato dal modulo Neighborhood insieme al MAC address dell'interfaccia di rete di b per produrre un WholeNodeUnicastID. Lo stub prodotto in questo modo trasmetterà su una sola interfaccia di rete, univocamente individuata dal INeighborhoodArc passato al metodo. Per il lato server vedremo sotto come il nodo b aveva istruito il suo modulo Neighborhood perché potesse gestire questo tipo di IUnicastID.

Come detto prima, nelle trasmissioni unicast è sempre individuato un solo arco tra a e b. Per le trasmissioni in UDP questo non è scontato. Infatti il messaggio è trasmesso solo su una interfaccia di a ma potrebbe essere rilevato da diverse interfacce di b. Per questo dobbiamo usare come IUnicastID un oggetto che individua uno specifico MAC address di b. Quindi il nodo b esamina il messaggio solo quando lo legge da quella particolare interfaccia e non dalle altre. Le trasmissioni unicast fatte dai moduli di nodo possono essere in TCP o in UDP, come vedremo in seguito. In UDP vengono in effetti fatte solo dallo stesso modulo Neighborhood in due situazioni: quando non ha ancora realizzato l'arco o quando lo ha appena rimosso.

In tutti i casi, quindi, il nodo b esamina il messaggio solo una volta.

Facciamo un altro esempio di un modulo di nodo in cui un nodo a vuole chiamare un metodo remoto su un set di nodi diretti vicini, diciamo b, c e d. Il nodo a chiama un metodo di Neighborhood per produrre uno stub di tipo whole_node_broadcast. Il modulo Neighborhood usa il suo NeigborhoodNodeID per produrre un WholeNodeSourceID. Inoltre in questo metodo il nodo passa i vari INeighborhoodArc di b, c e d; i relativi NeighborhoodNodeID (senza guardare i MAC address) saranno usati dal modulo Neighborhood per produrre un WholeNodeBroadcastID. Lo stub prodotto in questo modo trasmetterà su tutte le interfacce di rete gestite dal nodo a. Per il lato server vedremo sotto come i nodi, ad esempio b, c, d ed anche e, avevano istruito ognuno il suo modulo Neighborhood perché potesse gestire questo tipo di IBroadcastID.

Come detto prima, nelle trasmissioni broadcast non sono individuati specifici archi tra a e gli altri nodi. Quindi ogni nodo che riceve il messaggio potrebbe esaminarlo diverse volte. Diciamo quindi che, soprattutto per i moduli di nodo, le trasmissioni broadcast verso un set di nodi avvengono sempre su tutti gli archi esistenti.

Ovviamente anche lo stesso modulo Neighborhood, il quale è di per se un modulo di nodo, può usare in completa autonomia le modalità sopra esposte per effettuare chiamate Unicast e Broadcast.

Esaminiamo cosa avviene lato server. Una descrizione passo passo è presente in questo documento.

Abbiamo anticipato che, per gestire le comunicazioni lato server, all'inizio della sua attività il modulo Neighborhood deve essere istruito su come gestire le chiamate che riceve. L'utilizzatore del modulo dovrà dire al Neighborhood:

Il modulo viene subito inizializzato con le callback da chiamare per gestire le chiamate IdentityAware e lo skeleton da usare per le chiamate WholeNode. Di modo che è pronto a gestire le chiamate che il nodo potrà ricevere.

Grazie al framework ZCD, quando un metodo remoto viene invocato, l'implementazione del metodo riceve un oggetto chiamato CallerInfo. Con tale oggetto esso può identificare attraverso quale arco-nodo o arco-identità tale messaggio è pervenuto. Per realizzare questa associazione il modulo Neighborhood deve fornire essenzialmente due metodi:

Costituzione della prima identità - Associazioni mantenute dal nodo

Con il termine nodo indichiamo l'utilizzatore del modulo Neighborhood.

Quando il nodo a inizia l'attività, assume una identità che è la sua identità principale. Chiamiamola a0. Di fatto questo significa che crea un NodeID e crea una prima istanza di ogni modulo di identità.

Il nodo mantiene una associazione ns tra questa identità e il network namespace default. Lo indichiamo dicendo ns(a0) = "". La stringa vuota rappresenta il network namespace default, altrimenti avremmo il nome del network namespace.

Il nodo mantiene una associazione in tra questa identità e un'altra associazione. Questa associazione interna in(a0) (interfacce gestite da a0) è tra ogni interfaccia di rete reale gestita dal nodo e una struttura dati che rappresenta l'interfaccia gestita dall'identità.

Ad esempio: costruiamo la struttura dati n che identifica l'interfaccia "eth0". Abbiamo questi membri:

e poi diciamo che questa struttura è associata all'interfaccia reale "eth0" come viene gestita da a0:

Per la identità principale ap abbiamo sempre che ns(ap) = "" e in(ap)("xyz").dev = "xyz". Cioè la identità principale gestisce le interfacce reali che sono nel network namespace default.

Quando il modulo Neighborhood forma un arco i, questo rappresenta un collegamento tra una interfaccia di rete reale di a e una interfaccia di rete reale del nodo collegato, chiamiamolo b. Da questo momento il nodo mantiene una associazione f tra la coppia a0-i e un set di identità nel nodo b.

Dopo aver formato l'arco i il nodo viene a conoscenza (come lo fa non è di pertinenza del modulo Neighborhood) che sopra questo arco devono appoggiarsi n archi-identità tra a0 e le identità b0 ... bn-1. Viene a conoscere inoltre per ognuna di queste identità di b, sempre relativamente all'arco i, un MAC-address e un indirizzo di scheda. Memorizza tutti questi dati nell'associazione f.

Riassumendo, f(a0-i) è un set di oggetti che chiamiamo arco-identità. Un suo elemento, diciamo w, rappresenta l'arco-identità a0-bj che si appoggia sull'arco i. L'elemento w contiene:

Creazione di una nuova identità

Abbiamo detto che la creazione di una nuova identità di un nodo non è una scelta del modulo, ma del suo utilizzatore. Vediamo come questo avviene.

Esaminiamo il caso in cui, a fronte di una migrazione, il nodo corrente a crea una nuova identità a1, cioè un nuovo NodeID, basata su una sua precedente identità a0.

Tutte queste operazioni non coinvolgono direttamente il modulo Neighborhood. Esso resta comunque in grado, ricevendo dall'utilizzatore i NodeID aggiornati, di produrre uno stub per moduli di identità per comunicare dalla sua nuova identità ad uno o più diretti vicini. Resta anche in grado, dato un messaggio ricevuto che è per moduli di identità, di identificare, per mezzo delle callback ricevute all'inizio, se è per la sua nuova identità e da parte di chi.

Esaminiamo il caso in cui un nodo vicino b crea una nuova identità b1 basata su una sua precedente identità b0. La precedente identità b0 era collegata attraverso un arco i (o più di uno) alla identità del nodo corrente ak, la quale non è cambiata. Sia w l' arco-identità ak-b0 che si appoggia su i.

Tutte queste operazioni non coinvolgono direttamente il modulo Neighborhood. Esso resta comunque in grado, ricevendo dall'utilizzatore i NodeID aggiornati, di produrre uno stub per moduli di identità per comunicare da una sua identità alla nuova identità del vicino b. Resta anche in grado, dato un messaggio ricevuto che è per moduli di identità, di identificare, per mezzo delle callback ricevute all'inizio, se è per una sua identità da parte della nuova identità del vicino b.

Rimozione di un arco-identità

In un certo momento, l'utilizzatore del modulo decide che una certa identità del nodo corrente ak non deve avere più archi verso una certa identità di un suo vicino bj; quindi per ogni arco che il modulo Neighborhood aveva creato tra a e b, l'utilizzatore del modulo fa alcune operazioni per rimuovere gli archi-identità ak-bj.

In precedenza l'utilizzatore del modulo si era dovuto occupare di rimuovere (o cambiare) tutte le rotte che usavano quell'arco come gateway.

Tutte queste operazioni non coinvolgono direttamente il modulo Neighborhood.

Requisiti

Deliverables

Classi e interfacce

L'implementazione del sistema di tasklet è passata al modulo dal suo utilizzatore. Si tratta di una istanza dell'interfaccia ITasklet che è descritta nel relativo documento.


Una interfaccia di rete passata al modulo è un oggetto istanza di una classe di cui il modulo conosce l'interfaccia INeighborhoodNetworkInterface. Tramite questa interfaccia il modulo può:


La stub factory è un oggetto di cui il modulo conosce l'interfaccia INeighborhoodStubFactory. Tramite essa il modulo può:


Il manager di rotte e indirizzi è un oggetto di cui il modulo conosce l'interfaccia INeighborhoodIPRouteManager. Tramite essa il modulo può:

Il modulo lo usa per rendere possibile la comunicazione via TCP coi vicini tramite un indirizzo fisso. Il modulo associa ad ogni interfaccia di rete che gestisce un indirizzo detto indirizzo di scheda. Per ogni arco che realizza, il modulo aggiunge la rotta con scope link verso l'indirizzo di scheda dell'interfaccia del vicino collegata all'arco. Quando rimuove l'arco rimuove anche la rotta. Quando il modulo cessa di gestire un'interfaccia rimuove il relativo indirizzo.

Tramite questo meccanismo il modulo gestisce solo gli indirizzi di scheda della identità principale del nodo corrente, nel network namespace default. Allo stesso modo, esso imposta le rotte verso gli indirizzi di scheda della identità principale di ogni nodo vicino, sempre nel network namespace default. Per la gestione delle altre identità, sia come indirizzi propri sia come rotte verso gli indirizzi dei vicini, il nodo le gestisce in autonomia, senza l'intervento del modulo Neighborhood.


La classe usata per l'identificativo di una identità, cioè NodeID, è definita nella libreria Common. Il modulo Neighborhood ha una dipendenza su questa libreria, quindi conosce tale classe.

La conoscenza del modulo Neighborhood relativamente a tale classe si limita al fatto di sapere che essa è serializzabile secondo la modalità usata in JsonGlib.


La classe usata per l'identificativo di un nodo, cioè NeighborhoodNodeID, è interna al modulo Neighborhood. Anche essa è serializzabile secondo la modalità usata in JsonGlib.


Un arco è un oggetto (NeighborhoodRealArc) noto al modulo. Grazie alle informazioni memorizzate in esso (my_nic, mac) il modulo è in grado di evitare la creazione di ulteriori archi verso lo stesso vicino se non usano interfacce di rete distinte da ambo i lati. Sempre con le informazioni memorizzate in questo oggetto (nic_addr) il modulo è in grado di produrre lo stub che realizza la chiamata di un metodo remoto in TCP (reliable).

L'interfaccia dell'oggetto arco nota all'esterno del modulo, INeighborhoodArc, permette solo un sottoinsieme di operazioni:


Quando si chiama il metodo che produce uno stub per l'invio di messaggi in broadcast, può essere passato un oggetto che contiene il codice e i dati necessari a gestire l'evento di 'mancata ricezione di un ACK da un arco entro il timeout'. Tale oggetto implementa l'interfaccia INeighborhoodMissingArcHandler. L'interfaccia permette di:


Il costo di un arco può essere espresso con diverse metriche (latenza, larghezza di banda, ...). Attualmente l'implementazione del modulo misura la latenza e la esprime con un intero in microsecondi.

La latenza è il tempo che impiega un messaggio da noi a raggiungere il vertice collegato. In realtà quello che si può misurare, quindi quello che il modulo memorizza come costo, è il round-trip time (RTT).