Introduzione all'uso del simulatore di rete cnet

<< Installazione di cnet | Indice | Simulazioni: Il protocollo di data-link stop-and-wait >>

Introduzione alla simulazione basata sugli eventi

L'implementazione dei protocolli in cnet va fatta utilizzando uno stile di programmazione guidato dagli eventi (event-driven).

Con questo approccio è possibile gestire diversi nodi simultaneamente utilizzando un singolo processo, piuttosto che creare più processi di elaborazione nel sistema operativo (oppure in alternativa processi leggeri, spesso chiamati anche thread). Un vantaggio del modello a singolo processo basato sugli eventi è che è più semplice da implementare rispetto a quello multi-processo. D'altra parte un vantaggio dell'approccio multi-processo per la simulazione è che consente di sfruttare appieno la potenza di calcolo di più processori simultaneamente per condurre una singola simulazione molto complessa.

Anche se cnet è pensato principalmente per l'uso interattivo su macchine monoprocessori e quindi per simulazioni che non richiedono grosse potenze di calcolo, sono comunque possibili alcune ottimizzazioni, descritte nel manuale, che consentono la simulazione dei protocolli in modalità batch e su grossi volumi di dati in tempi in pratica accettabili per la maggior parte delle applicazioni e sicuramente nell'ambito della didattica delle reti.

Le caratteristiche peculiari dell'approccio event-based sono brevemente descritte di seguito. Questo approccio è da riternersi didatticamente valido perchè è lo stesso che viene tipicamente utilizzato in pratica per implementare i protocolli nei kernel dei sistemi operativi. Un sistema operativo generico, oltre che gestire la rete, deve infatti gestire molti altri eventi che riguardano il file-system e i dispositivi locali o l'esecuzione dei processi. Il modulo del sistema operativo che gestisce la rete viene spesso implementato con la strategia event-driven, ovvero esegue i suoi compiti il più velocemente possibile e poi restituisce subito il controllo al sistema per permettere l'esecuzione di altre attività. Nel nostro caso cnet svolge il ruolo del sistema operativo e quindi sviluppare protocolli con cnet è simile a implementare il supporto di rete per un vero sistema operativo!

Tutti i nodi eseguono una stessa copia del codice compilato che implementa il protocollo. Questo significa che ogni nodo ha la propria copia delle variabili definite in questo codice. Difatti i nodi simulano dei calcolatori distinti, che non condividono la RAM, ma possono comunicare solo attraverso lo strato Fisico.

Cnet implementa uno schedulatore di eventi. È lo schedulatore che avverte il codice che implementa il protocollo che si è verificato un evento di interesse. Il protocollo risponde quindi a questo evento nella maniera prevista, eseguendo il codice di una funzione detta gestore dell'evento (event handler).

Come fa lo schedulatore a sapere se l'evento è di interesse per il protocollo e in caso affermativo quale event handler del codice del protocollo deve essere chiamato, non avendo alcuna conoscenza della struttura del protocollo? La soluzione è semplice: tutte le funzioni di gestione degli eventi devono prima essere registrate presso lo schedulatore, per poter poi essere chiamate quando si verifica l'evento e ricevere le informazioni relative. La registrazione di un handler avviene tramite una chiamata alla funzione CNET_set_handler, facente parte della API offerta da cnet agli sviluppatori dei protocolli, durante la fase di inizializzazione nel codice del protocollo.

Più precisamente il codice del protocollo (di cui esiste una copia per ciascun nodo) deve obbligatoriamente definire almeno una funzione di callback (per default chiamata reboot_node) per ricevere l'evento iniziale EV_REBOOT. Questa funzione oltre ad allocare eventuale memoria dinamica necessaria all'implementazione del protocollo e inizializzare le variabili di stato utilizzate, avrà il compito di informare cnet su quali eventi il protocollo è interessato e quindi quali handler dovranno essere chiamati dal dispatcher di cnet quando si verificano questi eventi (per registrare un handler si utilizza appunto la funzione CNET_set_handler citata prima).

Gli eventi a cui un protocollo può rispondere sono di vario tipo. Questo elenco non è esaustivo, si faccia riferimento al manuale per maggiori dettagli:

EV_REBOOT
inizializzazione (reboot) del nodo (avviene per tutti i nodi nel momento in cui viene avviata la simulazione)
EV_APPLICATIONREADY
arrivo di un messaggio da parte dello strato Applicativo, ovvero un messaggio è pronto per essere consegnato
EV_PHYSICALREADY
ricezione di un frame dallo strato Fisico su un certo link (un nodo infatti può avere più link in una rete in cui è inserito)
EV_TIMER1..EV_TIMER10
scadenza di un timer impostato precedentemente su una delle 10 code di timer disponibili
EV_DEBUG1 .. EV_DEBUG5
selezione da parte dell'utente della simulazione di uno dei 5 tasti di debugging disponibili nella finestra di output del nodo
EV_SHUTDOWN
spegnimento (shutdown) del nodo (evento che avviene nel momento in cui il simulatore termina normalmente)

Quando si verifica un evento, l'handler registrato per rispondere a quel tipo di evento viene chiamato da cnet passandogli tre parametri, ma tutti possono essere ignorati in determinate condizioni.

Il primo è una costante simbolica che indica il tipo di evento verificatosi. Uno stesso handler potrebbe infatti gestire diversi tipi di eventi; se è stato registrato per rispondere ad un solo tipo di evento questo parametro può essere ignorato.

Il secondo parametro indica in modo univoco il timer che è scaduto. Se il tipo di evento (indicato dal primo parametro) non si riferisce alla scadenza di un timer impostato precedentemente, questo parametro assume il valore speciale NULLTIME e quindi in questo caso anche questo parametro si può ignorare.

Il terzo parametro è un puntatore ad alcuni dati, specificato nel momento in cui si registra l'handler e può essere utilizzato appunto per passare un riferimento a dati specifici mantenuti dal protocollo su cui l'handler ha bisogno di agire. Se non utilizzato, lo si imposta convenzionalmente al valore 0 o NULL e lo si ignora.

Affinchè l'approccio event-driven funzioni, i gestori degli eventi devono svolgere le operazioni per cui sono responsabili il più velocemente possibile, ovvero cercare di ritornare quanto prima per consentire allo schedulatore di invocare altri gestori. Infatti mentre un gestore degli eventi è attivo, esso non verrà mai interrotto dall'arrivo di un altro evento. Occorrerà aspettare che la gestione dell'evento corrente termini affinché possa essere gestito un ulteriore evento.

Un gestore non dovrebbe mai entrare in loop infinito, oppure mettersi in attesa per un periodo prefissato di tempo (sleep) oppure in attesa programmata di altri eventi (wait) o entrare in cicli che effettuano ripetutamente il controllo se un evento si è verificato o meno (poll). Questo tipo di comportamenti sono vietati nell'ambito dell'approccio event-based.


<< Installazione di cnet | Indice | Simulazioni: Il protocollo di data-link stop-and-wait >>