Modulo Neighborhood - Dettagli Tecnici
Contents
-
Modulo Neighborhood - Dettagli Tecnici
- Requisiti
- Deliverables
- Rilevamento dei vicini, costituzione degli archi, misurazione dei costi
- Produzione di uno stub per inviare un messaggio in broadcast
- Produzione di uno stub per inviare un messaggio UDP in unicast
- Produzione di uno stub per inviare un messaggio reliable ad un vicino tramite un arco
- Indirizzo IPv4 di scheda
- Proof of concept
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 ITasklet per fornire l'implementazione del sistema di tasklet.
Dopo istanzia il suo NeighborhoodManager passando al costruttore:
La callback per gestire gli IdentityAwareUnicastID (get_identity_skeleton).
La callback per gestire gli IdentityAwareBroadcastID (get_identity_skeleton_set).
Lo skeleton per gestire gli WholeNodeUnicastID e gli WholeNodeBroadcastID (node_skeleton).
Il numero massimo di archi (int max_arcs).
La stub factory (istanza di INeighborhoodStubFactory stub_factory).
Il manager di indirizzi (istanza di INeighborhoodIPRouteManager ip_mgr).
Dopo, per ogni interfaccia di rete che intende gestire, richiama sul NeighborhoodManager il metodo start_monitor(nic), dove nic è una INeighborhoodNetworkInterface.
Deliverables
Il modulo segnala l'avvenuta assegnazione dell'indirizzo di scheda ad una interfaccia di rete gestita attraverso il segnale nic_address_set di NeighborhoodManager.
In tale segnale viene riportato:
- Il nome dell'interfaccia di rete. Una stringa. Es. "eth0".
- L'indirizzo assegnato. Una stringa. Es. "169.254.23.45".
Il modulo segnala la costituzione di un arco attraverso il segnale arc_added di NeighborhoodManager.
In tale segnale viene riportato:
- L'arco costituito. Un INeighborhoodArc.
Il segnale significa anche che è stata aggiunta nelle tabelle (nel network namespace default) la rotta verso quell'indirizzo di scheda che è riportato nell'istanza di INeighborhoodArc.
Il modulo segnala la rimozione di un arco attraverso il segnale arc_removed di NeighborhoodManager.
In tale segnale viene riportato:
- L'arco rimosso. Un INeighborhoodArc.
Il segnale significa anche che è stata rimossa dalle tabelle (nel network namespace default) la rotta verso quell'indirizzo di scheda che è riportato nell'istanza di INeighborhoodArc.
Il modulo segnala la variazione del costo di un arco attraverso il segnale arc_changed di NeighborhoodManager.
In tale segnale viene riportato:
- L'arco. Un INeighborhoodArc.
Il modulo segnala l'avvenuta rimozione dell'indirizzo di scheda ad una interfaccia di rete che non si gestisce più attraverso il segnale nic_address_unset di NeighborhoodManager.
In tale segnale viene riportato:
- Il nome dell'interfaccia di rete. Una stringa. Es. "eth0".
Il modulo permette di ottenere l'elenco degli archi ora presenti con il metodo current_arcs di NeighborhoodManager.
Il modulo fornisce i metodi get_dispatcher e get_dispatcher_set di NeighborhoodManager per permettere al nodo di gestire i messaggi unicast e broadcast ricevuti.
Il modulo fornisce i metodi get_identity e get_node_arc di NeighborhoodManager per permettere al nodo di identificare il vicino (identità o nodo) che ha inviato un messaggio.
Il modulo permette di ottenere uno stub per inviare un messaggio reliable ad un vicino tramite un arco (o un arco-identità) con il metodo get_stub_whole_node_unicast (o get_stub_identity_aware_unicast) di NeighborhoodManager.
Il modulo permette di ottenere uno stub per inviare un messaggio in broadcast con i metodi get_stub_whole_node_broadcast (e get_stub_identity_aware_broadcast) 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 istanziato il NeighborhoodManager il modulo genera il suo NeighborhoodNodeID.
Quando viene chiamato il metodo start_monitor sulla istanza di NeighborhoodManager, 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 emette il segnale nic_address_set.
Poi avvia una tasklet nella quale invia un broadcast_to_dev (cioè un broadcast solo su quella interfaccia di rete) con il messaggio "ci sono io" indicando il suo NeighborhoodNodeID, 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 broadcast 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 messaggio "facciamo un arco" in UDP unicast, indicando anche esso il suo NeighborhoodNodeID 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 dell'oggetto INeighborhoodNetworkInterface, come indicato nel relativo documento.
Dopo che è stata fatta la prima misurazione, il modulo emette il segnale arc_added e l'arco va a far parte della lista ufficiale.
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 get_broadcast che restituisce un oggetto stub di tipo radice (un IAddressManagerStub) che effettua chiamate broadcast.
Quando vuole trasmettere un messaggio in broadcast il modulo chiama sempre subito prima questo metodo per ottenere uno stub nuovo. In questo metodo può indicare una istanza dell'interfaccia IAckCommunicator per ricevere dopo il timeout la lista dei MAC address che hanno segnalato con un ACK la ricezione del messaggio.
Il metodo riceve questi parametri:
- un ISourceID;
- un IBroadcastID;
un elenco di interfacce di rete (List<string> nics);
- opzionalmente una istanza di IAckCommunicator.
Un IBroadcastID può avere diverse forme per identificare quali nodi diretti vicini (o quali loro identità) siano i destinatari del messaggio. Individuiamo queste possibili classi che implementano IBroadcastID:
EveryWholeNodeBroadcastID. Indica che tutti i nodi che ricevono sono i destinatari del messaggio di nodo.
- Questo è usato dal modulo Neighborhood per i messaggi "ci sono io".
WholeNodeBroadcastID. Contiene un set di NeighborhoodNodeID. Indica che solo quei nodi sono i destinatari del messaggio di nodo.
IdentityAwareBroadcastID. Contiene un set di NodeID. Indica che solo quelle identità sono i destinatari del messaggio di identità.
Quando il modulo neighborhood (NeighborhoodManager) vuole inviare un messaggio in broadcast:
bcid = una istanza di IBroadcastID a seconda dei destinatari da raggiungere.
nics = lista di nomi di NIC a seconda dei destinatari da raggiungere.
comm = null.
- se desidera specificare un handler per gli archi che non hanno ricevuto il messaggio:
missing_handler = istanza di una classe a sua scelta che implementa INeighborhoodMissingArcHandler.missing come vuole; potrebbe essere necessario passare al costruttore un riferimento allo stesso NeighborhoodManager per richiamare i suoi metodi, ad esempio new NeighborhoodRemoveMissing(this) ; oppure, se si ha una callback da richiamare la si passa al costruttore, ad esempio new NeighborhoodActOnMissing(missing_callback) .
lst_expected = current_arcs_for_broadcast(nics); cioè memorizza in una lista gli archi che dovrebbero ricevere il messaggio.
comm = new NeighborhoodAcknowledgementsCommunicator ( nics, lst_expected, mgr=this, missing_handler ) ; questa classe implementa IAckCommunicator.process_macs_list(Gee.List<string> responding_macs) così:
lst_expected = intersezione(lst_expected, mgr.current_arcs_for_broadcast(nics)); cioè usa nuovamente il metodo NeighborhoodManager.current_arcs_for_broadcast; solo gli archi che esistevano prima e esistono ora vanno verificati.
per ogni missed in lst_expected tale che missed.mac not in responding_macs:
- lancia una nuova tasklet in cui:
- missing_handler.missing(missed) ; cioè chiama il metodo 'missing' nell'istanza di INeighborhoodMissingArcHandler, passando l'arco mancato.
- lancia una nuova tasklet in cui:
- stub = stub_factory.get_broadcast(bcid, nics, comm).
- chiama il metodo che vuole sullo stub.
Se si è passata comm, l'istanza di IAckCommunicator opzionale, allora la chiamata del metodo remoto deve seguire immediatamente la creazione dello stub, perché la prima chiamata a current_arcs_for_broadcast viene eseguita subito e la seconda viene eseguita dopo il timeout che parte al momento della chiamata del metodo remoto.
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. La differenza sta nella costruzione della istanza di IBroadcastID.
Uno stub è necessario al modulo Neighborhood quando deve trasmettere un messaggio in broadcast per rilevare nuovi archi o nodi. In questa occasione quello che serve è un EveryWholeNodeBroadcastID. E non serve un INeighborhoodMissingArcHandler.
Quando uno stub è necessario ad un modulo di nodo (che non sia il Neighborhood) quel modulo (o comunque l'utilizzatore del modulo Neighborhood) deve indicare quali nodi vanno raggiunti. Deve cioè fornire un set di INeighborhoodArc da cui il modulo Neighborhood estrapola un set di NeighborhoodNodeID con cui compone un WholeNodeBroadcastID. Può inoltre fornire un INeighborhoodMissingArcHandler. Il metodo pubblico di NeighborhoodManager a questo scopo è get_stub_whole_node_broadcast.
Quando uno stub è necessario ad un modulo di identità quel modulo (o comunque l'utilizzatore del modulo Neighborhood) deve indicare quali identità vanno raggiunte. Deve cioè fornire un set di NodeID con cui il modulo Neighborhood compone un IdentityAwareBroadcastID. Può inoltre fornire un INeighborhoodMissingArcHandler. Il metodo pubblico di NeighborhoodManager a questo scopo è get_stub_identity_aware_broadcast.
Produzione di uno stub per inviare un messaggio UDP in unicast
L'interfaccia INeighborhoodStubFactory permette permette con il metodo get_unnicast 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 ISourceID;
- un IUnicastID;
- una interfaccia di rete (string);
- un boolean per indicare se si vuole attendere la processazione.
Un IUnicastID prodotto per un messaggio da trasmettere in UDP ha solo una forma:
NoArcWholeNodeUnicastID. Contiene il NeighborhoodNodeID e il MAC address a cui il messaggio è indirizzato. Solo il nodo che ha quel NeighborhoodNodeID e solo quando riceve il messaggio attraverso quella interfaccia, si riconosce come destinatario del messaggio di nodo. Anche se l'arco non esiste ancora.
- Questo è usato esclusivamente dal modulo Neighborhood, per i messaggi "facciamo un arco" e "rimuovi un arco".
Il modulo Neighborhood può aver bisogno internamente di comunicare con un suo vicino prima di aver realizzato un arco; in questo caso produce questo tipo di stub con questo tipo di IUnicastID. Come istanza di ISourceID viene usata una istanza della classe WholeNodeSourceID.
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 con il metodo get_tcp al modulo anche di ottenere uno stub per inviare un messaggio reliable ad un particolare vicino tramite un particolare arco, dati questi parametri:
- un ISourceID;
- un IUnicastID;
- l'indirizzo di scheda del vicino su quell'arco (vedi sotto);
- un boolean per indicare se si vuole attendere la processazione.
Un IUnicastID prodotto per un messaggio da trasmettere in TCP può avere diverse forme per identificare quale nodo diretto vicino (o quale sua identità) sia il destinatario del messaggio. Individuiamo queste possibili classi che implementano IUnicastID:
- WholeNodeUnicastID. Non contiene dati, comunque il messaggio è in TCP quindi sarà processato da un solo nodo e una sola volta.
- IdentityAwareUnicastID. Contiene un NodeID.
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 'add_address'.
Quando si smette di gestire l'interfaccia, il modulo rimuove anche l'indirizzo locale dalla interfaccia, con il metodo '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:
- mette l'indirizzo di scheda del vicino come link diretto (associato al suo giusto nic e avendo come source preferito il suo indirizzo di scheda) nelle tabelle di routing, con il metodo 'add_neighbor';
- in una nuova tasklet, periodicamente crea un TCPClient verso l'indirizzo di scheda del vicino e verifica che l'arco è ancora funzionante altrimenti lo rimuove.
Alla rimozione di un arco il nodo:
- rimuove l'indirizzo di scheda del vicino dalle tabelle di routing, con il metodo 'remove_neighbor';
- rimuove la tasklet che lo monitorava.
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.
Proof of concept
Come proof of concept è stato realizzato un programma, neighborhoodclient, che si avvale del modulo Neighborhood per:
Assegnare indirizzi di scheda alle interfacce che gestisce.
- Individuare e realizzare archi con i nodi vicini.
- Impostare le rotte verso i diretti vicini.
Si tratta di un programma specifico per un sistema Linux.
Durante l'esecuzione del programma, l'utente può verificare che le rotte verso i diretti vicini vengano correttamente e tempestivamente realizzate e rimosse (ad esempio se un nodo muore o diventa irragiungibile tramite l'arco).
Il programma consente anche di verificare il modus operandi che è stato individuato (e descritto nel documento di analisi) per realizzare:
La creazione di una nuova identità.
La creazione di un arco-identita.
La rimozione di un arco-identità.
La rimozione di una vecchia identità.
Questo programma crea e rimuove anche i network namespace e le pseudo-interfacce da assegnare alle identità che il nodo assume, distinte dalla principale.
Il programma fornisce anche una classe che prevede dei metodi remoti come modulo di identità e una che prevede dei metodi remoti come modulo di nodo. Tali classi usano il modulo Neighborhood per gestire le comunicazioni lato client e lato server, L'utente può verificare che un metodo remoto può essere chiamato da un nodo su un suo diretto vicino. Nel caso del modulo di identità può verificare che la giusta identità reagisce sul nodo vicino, ma solo se il corrispettivo arco-identità è presente.
Inoltre il programma interattivamente consente di chiedere al modulo Neighborhood le informazioni che ha raccolto e mostrarle all'utente.
Di seguito descriviamo le operazioni svolte da questo programma. Sarà interessante anche perché alcuni aspetti analizzati qui saranno ripresi nella realizzazione del demone ntkd completo.
Interazione del programma con l'utente
Il programma neighborhoodclient prevede che l'utente immetta, come argomenti della riga di comando e in modo interattivo dalla console durante la sua esecuzione, tutti i requisiti del modulo. Anche i parametri che normalmente sarebbero individuati in modo autonomo dal demone ntkd (per esempio l'identificativo delle identità) nel caso del neighborhoodclient sono espressamente indicati dall'utente, questo per rendere più facilmente riproducibili gli ambienti di test.
I parametri passati all'avvio del programma neighborhoodclient sono:
- first_id
- max_arcs
I comandi che l'utente può dare interattivamente sulla console del programma neighborhoodclient sono:
- info
- Mostra le informazioni che il nodo ha.
- help
- Mostra un elenco dei comandi.
manage-nic <mio-dev>
- Inizia a gestire una interfaccia di rete.
add-arc <id-arco> <mio-id> <suo-id>
add-id <mio-vecchio-id> <mio-nuovo-id> [<id-arco> <suo-vecchio-id> <suo-nuovo-id>] [...]
remove-arc <id-arco> <mio-id> <suo-id>
remove-id <mio-vecchio-id>
whole-node-unicast <id-arco> -- <argomento>
whole-node-broadcast <id-arco> [<id-arco> ...] -- <argomento>
identity-aware-unicast <id-arco> <mio-id> <suo-id> -- <argomento>
identity-aware-broadcast <mio-id> <suo-id> [<suo-id> ...] -- <argomento>
Il significato di comandi e parametri sarà chiarito in seguito.
Creazione della identità principale
La identità principale del nodo viene creata automaticamente dal demone ntkd all'inizio della sua attività. Nel caso del programma neighborhoodclient, l'utente specifica sulla linea di comando l'identificativo (un intero) da assegnare a tale prima identità del nodo.
Codice id-arco
Quando il modulo Neighborhood segnala al programma neighborhoodclient che ha realizzato un arco, questo programma gli assegna un numero identificativo che chiamiamo id-arco e lo mostra sulla console all'utente. Questo numero serve solo all'utente per indicare nei suoi comandi quel particolare arco. Non ha un suo corrispettivo in nessun concetto applicabile al demone ntkd.
Archi identità
Quando un nodo rileva un diretto vicino tramite una sua interfaccia e forma con esso un arco, su quell'arco non appoggia immediatamente nessun arco-identità. Su quell'arco possono da subito passare delle comunicazioni del modulo di nodo.
È l'utilizzatore del modulo Neighborhood, in questo caso il programma neighborhoodclient su istruzione dell'utente, a decidere quali archi-identità formare.
Ad esempio, supponiamo che il programma neighborhoodclient è stato avviato sul nodo a indicando come identificativo della sua identità principale il numero 123. Sul nodo b è stato avviato indicando come identificativo della sua identità principale il numero 456. Dopo un po' il programma neighborhoodclient segnala sulla console del nodo a di aver realizzato un arco id-arco=1 con il nodo b (sulla console compariranno i MAC address delle interfacce di rete end-point dell'arco e l'utente saprà riconoscere il nodo b).
A questo punto l'utente in via interattiva sulla console del programma in esecuzione sul nodo a chiederà di formare sull'arco id-arco=1 un arco-identità tra 123 e 456. Cosa analoga sulla console del nodo b che avrà anch'esso indicato la formazione dell'arco.
A questo punto su questo arco-identità potranno passare anche delle comunicazioni del modulo di identità.
Creazione di nuove identità, rimozione di vecchie identità
Vi sono alcuni eventi che nel demone ntkd potranno portare alla creazione di una nuova identità: migrazione, costituzione di un percorso fisso per sfruttare i percorsi disgiunti, ... In questo proof of concept ci soffermeremo solo sul caso della migrazione, simulando cioè le operazioni che il demone ntkd dovrà fare in questi scenari.
A fronte di una migrazione, una nuova identità del nodo, chiamiamola ak, viene creata partendo da una delle sue identità, chiamiamola aj, la quale può essere la principale o anche no. Tutti gli archi-identità che partivano dalla ak vengono duplicati automaticamente sulla aj.
Inoltre, un arco-identità che collegava ak ad una identità bi del nodo diretto vicino b, quando viene duplicato sulla aj la collegherà a bi solo se bi non ha partecipato alla stessa migrazione. Se invece bi ha partecipato alla stessa migrazione, allora il nuovo arco-identità collegherà aj a una nuova identità bh che è stata creata sul nodo b partendo dalla bi.
In seguito alcuni archi-identità verranno rimossi dalla ak.
Nel programma neighborhoodclient questo evento viene simulato quando l'utente ne fa richiesta sulla console. Vediamo in che modo l'utente che interagisce con il programma neighborhoodclient può dare tutte le indicazioni per simulare questo scenario.
Supponiamo di avere i nodi a, b, c, d, e sui quali è in esecuzione il programma neighborhoodclient. Questi nodi sono disposti secondo il disegno:
Su ogni nodo viene avviato il programma neighborhoodclient, specificando sulla linea di comando l'identificativo numerico da assegnare alla prima identità principale. Indichiamo queste identità (e il relativo numero identificativo) con a0, b0, c0, d0, e0.
Dopo un certo tempo, il modulo Neigorhood avrà formato degli archi in base alla topologia rappresentata nel disegno sopra. Questi li indichiamo con a-b, b-c, a-c, b-e, a-d.
Poi l'utente interagisce dalla console con il programma neighborhoodclient in ogni nodo e lo istruisce riguardo la creazione degli archi-identità:
a0-b0 si appoggia sull'arco a-b.
Quindi le istruzioni a tal riguardo sono date sulla console del nodo a e su quella del nodo b in questo modo:
Sul nodo a l'utente dice: crea sull'arco a-b un arco-identità dalla mia identità a0 alla sua identità b0. Nel dettaglio gli argomenti di questo comando sono:
a-b - l'identificativo id-arco dell'arco.
a0 - il numero identificativo dell'identità di partenza nel nodo a.
b0 - il numero identificativo dell'identità di destinazione nel nodo b.
Sul nodo b l'utente dice: crea sull'arco b-a un arco-identità dalla mia identità b0 alla sua identità a0.
In modo analogo sui seguenti archi-identità.
b0-c0 si appoggia sull'arco b-c.
a0-c0 si appoggia sull'arco a-c.
b0-e0 si appoggia sull'arco b-e.
a0-d0 si appoggia sull'arco a-d.
Adesso le identità a0 e b0 migrano dando luogo alle nuove identità a1 e b1 che diventano le identità principali dei nodi a e b.
Per simulare questo evento, l'utente effettua queste operazioni:
Sulla console del nodo a chiede la costituzione della identità a1 basata sulla precedente a0; specifica inoltre che nella stessa migrazione l'identità b0 che si raggiungeva dall'identità a0 tramite l'arco a-b ha dato luogo alla nuova identità b1; gli altri archi-identità vanno replicati esattamente. Nel dettaglio gli argomenti di questo comando sono:
a0 - il numero identificativo dell'identità di partenza nel nodo a.
a1 - il numero identificativo della nuova identità nel nodo a.
- un set di associazioni, ognuna delle quali è una struttura dati che contiene:
a-b - l'identificativo id-arco dell'arco.
b0 - il numero identificativo dell'identità di partenza del nodo collegato, che ha migrato con noi.
b1 - il numero identificativo della nuova identità del nodo collegato, che ha migrato con noi.
Analogamente, sulla console del nodo b chiede la costituzione della identità b1 basata sulla precedente b0; specifica inoltre che nella stessa migrazione l'identità a0 che si raggiungeva dall'identità b0 tramite l'arco b-a ha dato luogo alla nuova identità a1; gli altri archi-identità vanno replicati esattamente.
Sulla console del nodo c chiede la costituzione di un nuovo arco-identità sull'arco c-a che collega la identità c0 con a1.
Analogamente, sulla console del nodo c chiede la costituzione di un nuovo arco-identità sull'arco c-b che collega la identità c0 con b1.
Analogamente, sulla console del nodo d chiede la costituzione di un nuovo arco-identità sull'arco d-a che collega la identità d0 con a1.
Analogamente, sulla console del nodo e chiede la costituzione di un nuovo arco-identità sull'arco e-b che collega la identità e0 con b1.
In seguito viene rimosso l' arco-identità b0-e0. Il motivo di questa rimozione è spiegato nel documento del modulo QSPN, riguarda i cluster di nodi e le identità di connettività.
Per simulare questo evento, l'utente effettua queste operazioni:
Sulla console del nodo b chiede la rimozione dell' arco-identità che poggia sull'arco b-e e collega b0 a e0. Nel dettaglio gli argomenti di questo comando sono:
b0 - il numero identificativo dell'identità di partenza nel nodo b.
e0 - il numero identificativo dell'identità di destinazione nel nodo e.
b-e - l'identificativo id-arco dell'arco.
Analogamente, sulla console del nodo e chiede la rimozione dell' arco-identità che poggia sull'arco e-b e collega e0 a b0.
Nel disegno evidenziamo i cluster. Risulta più chiaro che la migrazione delle identità principali di a e b da un cluster all'altro ha reso necessaria la presenza delle identità di connettività di a e b nel primo cluster per mantenerlo internamente connesso. Risulta altresì chiaro perché è stato rimosso un arco-identità: perché una identità di connettività mantiene collegamenti solo all'interno del cluster che essa supporta. Evidenziamo anche le identità di connettività con un asterisco.
Infine l'identità b0 si accorge di non essere necessaria alla connettività interna del primo cluster, quindi si auto-distrugge.
Per simulare questo evento, l'utente effettua queste operazioni:
Sulla console del nodo b chiede la rimozione della identità b0.
Sulla console del nodo a chiede la rimozione dell' arco-identità che poggia sull'arco a-b e collega a0 a b0. Nel dettaglio gli argomenti di questo comando sono:
a0 - il numero identificativo dell'identità di partenza nel nodo a.
b0 - il numero identificativo dell'identità di destinazione nel nodo b.
a-b - l'identificativo id-arco dell'arco.
Analogamente, sulla console del nodo c chiede la rimozione dell' arco-identità che poggia sull'arco c-b e collega c0 a b0.