Manuale del Network Simulator 2 v12

Transcript

Manuale del Network Simulator 2 v12
DIIT
Dipartimento di Ingegneria Informatica e delle Telecomunicazioni
Facoltà di Ingegneria
Manuale “Rapido” del Network Simulator 2
V. 1.2
a cura dell’Ing. Fernando Menta
Novembre 2001
1. Introduzione
Il Network Simulator 2 o ns2 è un programma in grado di simulare il comportamento di una rete
qualsiasi presa in esame dall’utente e di fornirne i risultati desiderati.
Inizialmente l’ns è stato sviluppato solo in ambiente Unix, solo di recente è disponibile una versione
anche per Windows95/98/2000, quindi è chiaro che in quanto a documentazione, affidabilità e
disponibilità, l’ns in ambiente Unix è preferibile, infatti tutto il lavoro di ricerca al momento viene
eseguito sotto questa piattaforma.
1.1. Uso del simulatore
Sia in Unix che in Windows si lavora in un contesto a riga di comando (per esempio sotto Windows
si usa il prompt del DOS) per lanciare il simulatore.
L’input del simulatore è costituito da un file di testo che contiene tutte le informazione sulla rete da
simulare, quindi si esegue l’ns digitando sul prompt:
ns miarete.tcl <invio>
Dopo di ciò si attende che il simulatore termini (il tempo di attesa dipende dalla complessità della
rete, ma soprattutto dalla lunghezza della simulazione e dai bit-rate in gioco), esso fornirà un file di
output che potrà essere analizzato con diversi strumenti.
ns.exe
Miarete.tcl
Out.nam
Il file di input è un file di testo con estensione TCL (Tool Command Language), esso contiene sia
le specifiche della rete da esaminare, che le direttive del simulatore (fase di schedulazione), sotto
forma di linguaggio script (TCL). E’ chiaro allora che questo linguaggio rappresenta il cuore
dell’ns, perché tramite esso possiamo impostare la topologia della rete, le specifiche dei vari link e
soprattutto i vari protocolli di rete e di trasporto che entrano in competizione nella rete.
Le direttive del simulatore sono costituite dal tempo di simulazione, dalla gestione in tempo reale
della simulazione e dalla gestione del file di output che può essere personalizzata.
2
Le istruzioni che compongono il linguaggio TCL per ns si trovano documentate nel file nsman.html.
1.2. Descrizione del simulatore
La potenza dell’ns sta nel fatto che non ha praticamente nessun limite nel gestire le simulazioni, in
quanto riesce ad integrare e a comprendere tutti i livelli di una connessione dal livello fisico fino al
livello applicativo; inoltre esso è espandibile ed è attualmente in espansione, e tutti possono
contribuire ad espanderlo. Infatti per l’ns sono disponibili i file sorgente scritti in linguaggio C++, e
tramite una profonda conoscenza dell’ns, del C++ e del linguaggio TCL è possibile implementare
nuovi protocolli personali con nuovi comandi TCL inseriti dall’utente, e quindi ricompilare il tutto
in modo da ottenere un nuovo ns.exe in grado di comprendere tali nuovi comandi.
Attualmente (ns versione 2.1 beta 8) è possibile gestire le seguenti entità:
1.2.1. Livello fisico:
-bit-rate
-tempo di ritardo
1.2.2. Livello data-link:
-bidirezionalità del link
-LAN
-protocollo di MAC: CSMA/CD
-gestione automatica degli errori con modello statistico di errore
Livello di rete:
-instradamento automatico con algoritmo di Dijkstra
-gestione della coda:
Droptail
FQ
SFQ
DRR
RED
CBQ
-Unicast routing e multicast routing.
Livello di trasporto:
-protocolli TCP:
3
Tahoe
Reno
Newreno
Vegas
Sack1
Fack
Fulltcp
-altri protocolli:
UDP
RTP
RTCP
RAP
TFRC
Livello di applicazione:
-sorgenti di traffico:
CBR (constant bit rate)
TELNET
FTP
-altre sorgenti programmabili sono:
traffico ON/OFF di tipo esponenziale
traffico ON/OFF con distribuzione paretiana
traffico predefinito in un file apposito.
-Interazione tra siti web con protocollo http.
Le applicazioni che rappresentano le nostre sorgenti di traffico dati, vengono affidate ai protocolli
di trasporto. Sorgenti di traffico particolari quali video, audio ed altri tipi di dati devono essere
modellizzate con gli strumenti già presenti, oppure create ad hoc ed inserite nella libreria TCL. Sia
le sorgenti di traffico che tutti i vari protocolli supportati sono corredati con tutti i loro possibili
parametri, che possono essere modificati anche in tempo reale.
E’ possibile implementare reti wire-less e satellitarie.
1.3. Accessori
Per esaminari i dati di output del simulatore è possibile utilizzare due programmi in dotazione con
l’ns, che sono il NAM (Network Animator) e l’Xgraph (solo per Unix).
4
Il NAM permette di visualizzare graficamente la topologia creata col file TCL ed i flussi di dati tra i
vari nodi in tempo reale, compresa la perdita dei pacchetti effettuata dal controllo di congestione dei
router. E’ anche possibile visualizzare dei semplici grafici qualitativi sulla bontà del collegamento.
L’ Xgraph è un programma specializzato solo in grafici.
E’ infine possibile visualizzare i risultati di qualsiasi parametro semplicemente attaccando dei flowmonitor nei link di interesse e leggendo periodicamente dati che è possibile memorizzare in un file
di testo (vedere ns-man).
1.4. Note per chi legge
Tutte le parole in corsivo che seguiranno, indicheranno parole chiave del simulatore, mentre le
parole non in corsivo saranno quelle che possono essere definite a piacere dall’utente.
Le parole racchiuse tra < > hanno un significato astratto e possono essere sia variabili che numeri.
5
2. Classe Simulator
Abbiamo già detto che l’ns è sviluppato essenzialmente in linguaggio C++, precisamente esso è
costituito da una collezione di classi che descrivono le varie entità del simulatore. La classe più
importante è la classe Simulator, in quanto, per effettuare una simulazione occorre prima di tutto
creare un oggetto Simulator, esso identifica la simulazione stessa. Per creare un oggetto Simulator
occorre scrivere:
set ns [new Simulator]
in questo modo la variabile ns sarà un oggetto simulazione, ovvero la simulazione stessa.
Il simulatore viene pilotato ad eventi, gli eventi sono forniti dal cosiddetto ‘schedulatore’, esso si
occupa di eseguire gli eventi in ordine di tempo ed uno alla volta (single threaded); se più eventi
risultano essere schedulati nello stesso istante, allora essi verranno eseguiti in ordine di
schedulazione. Esistono quattro tipi di schedulatori derivati dalla classe Scheduler, ognuno dei quali
è implementato usando strutture dati differenti:
•
list;
•
heap;
•
calendar queue (è quello di default);
•
real-time.
2.1.1. List (classe Scheduler/List)
Viene implementato con una semplice struttura a lista i cui elementi sono gli eventi della
simulazione sistemati in ordine crescente di tempo. L’inserzione o la cancellazione di un evento
richiede una scansione della lista per trovare il punto di inserzione o di cancellazione, quindi tale
operazione può richiedere parecchio tempo se il numero di eventi è elevato (proporzionale ad n).
2.1.2. Heap (classe Scheduler/Heap)
Con questo schedulatore la struttura cambia da semplice lista ad una struttura heap, essa risulta
essere conveniente quando abbiamo un elevato numero di eventi, per cui l’inserzione o la
cancellazione di un evento viene ottimizzata, e richiede un tempo proporzionale a O(log n), dove
con n si indica il numero di eventi. Il funzionamento di questo schedulatore non è stato ancora
completamente verificato.
2.1.3. Calendar (classe Scheduler/Calendar)
Questo schedulatore usa una struttura dati analoga ad un calendario, la cui descrizione formale è
stata data da R. Brown.
6
2.1.4. RealTime (classe Scheduler/RealTime)
Questo schedulatore cerca di sincronizzare l’esecuzione degli eventi in tempo reale. Essa è quindi
utile in fase di emulazione, quando andiamo ad interfacciare la nostra rete simulata, con una rete
reale esterna al nostro elaboratore.
2.2. Metodi
La classe Simulator implementa una serie di metodi, indispensabili per imbastire la simulazione:
•
use-scheduler <schedulatore>: specifica il tipo di schedulatore da usare nella simulazione, per
default viene usato lo schedulatore Calendar;
•
now: restituisce il tempo corrente in cui si trova la simulazione, es.:
set time [$ns now]
•
at <time> <evento>: schedula l’evento specificato nel tempo specificato in secondi, es.:
$ns at 10 “$ftp start”
fa partire una sorgente ftp all’istante 10;
•
run: lancia lo schedulatore e quindi la simulazione, es.:
$ns run
•
halt: mette in pausa lo schedulatore;
•
namtrace-all <file handler>: abilita la memorizzazione dei dati della simulazione istante per
istante nel file indicato da <file handler> (vedi appendice A.2).
7
3. Livello Fisico
3.1. Creare la topologia di rete
3.1.1. Nodi
La nostra rete sarà composta essenzialmente da vari nodi interconnessi tra loro tramite link. Per
creare l’istanza di un nodo occorre scrivere:
set mio_nodo [$ns node]
In questo caso ‘mio_nodo’ rappresenta l’istanza di un generico nodo nel caso molto comune di flat
addressing-routing. Se invece si vuole creare una topologia gerarchizzata è necessario specificare
per ogni nodo un numero aggiuntivo corrispondente al suo livello gerarchico:
set mio_nodo [$ns node <x>]
dove x rappresenta un numero intero (es: 1,2,3,…)
3.1.2. Links
Tra due generici nodi possono essere definiti links unidirezionali o bidirezionali:
$ns simplex-link <nodo1> <nodo2> <bw> <delay> <tipo_di_coda>
simplex-link non fa altro che creare un link unidirezionale dal nodo1 al nodo2, invece:
$ns duplex-link <nodo1> <nodo2> <banda> <ritardo> <tipo_di_coda>
crea un link bidirezionale tra il nodo1 ed il nodo2, duplex-link è equivalente a due simplex-link: uno
dal nodo1 al nodo2, ed uno dal nodo2 al nodo1. Questa istruzione crea un oggetto link contenente i
seguenti parametri:
•
bandwidth_: rappresenta la capacità del link espressa in bit/s;
•
delay_: rappresenta il tempo di propagazione del segnale espresso in secondi, quindi,
indirettamente, rappresenta la lunghezza del link;
•
<tipo_di_coda> rappresenta il tipo di active queue management (AQM) utilizzato nel router del
link (DropTail, RED, ecc.); i vari tipi di gestione delle code verranno illustrati nel seguente
capitolo.
Il link può essere istanziato come un oggetto con il seguente codice:
set mio_link [[$ns link <nodo1> <nodo2>] link]
cioè la variabile ‘mio_link’ sarà un’istanza del relativo link specificato univocamente dai due nodi.
A questo punto è possibile cambiare in qualsiasi momento sia la banda che il ritardo del link con i
seguenti metodi:
$ns bandwidth <nodo1> <nodo2> <banda>
8
oppure:
$mio_link set bandwidth_ <val>
Nel primo metodo il link viene specificato esplicitamente con i nodi, invece nel secondo viene
specificato implicitamente tramite l’istanza ‘mio_link’. Allo stesso modo è possibile modificare il
ritardo del link sostituendo nelle due istruzioni precedenti la parola chiave delay al posto di
bandwidth.
9
4. Livello di Rete
4.1. Gestione delle code
La gestione delle code è implementata mediante vari oggetti coda che discendono tutti dalla classe
Queue, essi vengono qui di seguito descritti.
4.1.1. Queue
E’ la classe generale degli oggetti coda, i suoi parametri fondamentali sono:
•
limit_: (default: 50) capacità del buffer in pacchetti;
•
blocked_: (default: false) indica se la coda è bloccata, cioè incapace di trasmettere pacchetti;
•
unblock_on_resume_: (default: true) indica che una coda dovrebbe sbloccarsi nel momento in
cui l’ultimo pacchetto spedito è stato trasmesso(ma non necessariamente ricevuto).
Per modificare la capacità del buffer limit_, vi sono due possibilità:
$ns queue-limit <n1> <n2> <limit>
oppure:
set mio_link [[$ns link <nodo1> <nodo2>] queue]
$mio_link set limit_ <val>
n1 è il nodo che ospita il buffer, mentre n2 ed n1 identificano il link associato al buffer da
modificare.
Dalla classe Queue sono stati derivati i seguenti oggetti:
4.1.2. DropTail
Essa implementa una semplice coda FIFO in cui i pacchetti che giungono dalle varie sorgenti ad
essa connesse vengono memorizzati nel buffer e poi spediti; nel caso in cui non vi sarà più spazio
nel buffer per allocare ulteriori pacchetti, essi verranno irrimediabilmente scartati. Per questo tipo di
oggetto non sono previsti né metodi, né parametri e né variabili di stato.
4.1.3. FQ (Fair Queueing)
Implementa un algoritmo che tenta di allocare per ciascun flusso le stesse risorse di buffer (ed
indirettamente le stesse risorse di banda), distinguendo ciascun flusso in base alle informazioni
estrapolate dall’header di pacchetto (ID di nodo o di pacchetto). Lo sforzo computazionale
di
questo algoritmo è notevole, ed aumenta col numero di flussi da gestire. Il numero massimo di
flussi gestibile per garantire la fairness è fissato a 32.
Parametri:
10
•
secsPerByte_: (default: 0) nessuna descrizione.
4.1.4. SFQ (Stochastic Fair Queueing)
Implementa la stessa filosofia dell’FQ, ma in maniera differente. Usa delle tabelle di hash per
indirizzare i pacchetti verso le code corrispondenti. Le garanzie di fairness sono probabilistiche e
dipendono dalla dimensione dell’indice di hash rispetto al numero di flussi trattati dal router.
Parametri:
•
maxqueue_: (default: 40) nessuna descrizione;
•
buckets_: (default: 16) numero totale di secchi da usare per la tabella di hash, quindi il numero
totale di flussi consentiti.
4.1.5. DRR (Deficit Round Robin)
Implementa la stessa filosofia dell’FQ, ma in maniera differente. Esso infatti cerca di risolvere i
problemi di unfairness che possono scaturire se le dimensioni dei pacchetti spediti variano da flusso
a flusso.
Parametri:
•
buckets_: (default: 16) numero totale di secchi da usare per la tabella di hash;
•
blimit_: (default: 25000) numero totale di bytes consentiti su tutti i flussi;
•
quantum_: (default: 250) numero totale di bytes che un flusso può spedire;
•
mask_: (default: 0) se settato ad 1, significa che un particolare flusso consiste di pacchetti
aventi lo stesso ID di nodo (e possibilmente ID di porta differente), altrimenti un flusso consiste
di pacchetti aventi lo stesso ID sia di nodo che di porta.
4.1.6. RED (Random Early Detection)
Questa politica di gestione della coda attua uno scarto preventivo e casuale dei pacchetti ancor
prima che il buffer vada in saturazione. Essa non fa altro che calcolare la coda media, ed in base ad
essa stabilire la probabilità di scarto dei singoli pacchetti che giungono al router.
I quattro parametri fondamentali che governano la probabilità di scarto sono:
•
q_weight_: (default: 0.002) peso utilizzato nell’algoritmo per il calcolo della coda media (è una
sorta di filtraggio passa-basso della coda istantanea);
•
thresh_: (default: 5) soglia minima per la coda media in pacchetti, al di sotto di questo valore la
probabilità di scarto è nulla;
•
maxthresh_: (default: 15) soglia massima per la coda media in pacchetti, quando la coda media
raggiunge questo valore la probabilità di scarto vale 1/linterm;
11
•
linterm_: (default: 10) al variare della coda media tra thresh_ e maxthresh_, la probabilità di
scarto varia tra 0 e 1/linterm.
Variabili di stato:
•
curq_: valore della coda in pacchetti;
•
ave_: valore della coda media in pacchetti;
•
prob1_: probabilità di scarto.
Altri parametri configurabili sono:
•
bytes_: (default: false) abilita il byte-mode, con cui la dimensione del pacchetto in arrivo
influisce sulla probabilità di scarto;
•
queue-in-bytes_: (default: false) abilita la misura della dimensione della coda media ave_ in
bytes anziché in pacchetti. Se abilitata, questa opzione fa in modo di moltiplicare i parametri
thresh_ e maxthresh_ per il valore contenuto in mean_pktsize_;
•
wait_: (default: true) abilita la distribuzione temporale uniforme dello scarto dei pacchetti;
•
setbit_: (default: false) abilita il settaggio del “congestion indication bit” presente nell’header
dei pacchetti, anziché effettuare lo scarto diretto dei pacchetti;
•
drop_tail_: (default: true) abilita lo scarto dei pacchetti che giungono al router quando la coda
media del RED eccede il valore maxthresh_;
•
gentle_: (default: false) attiva la proprietà di incrementare la probabilità di scartare pacchetti
prob1_, quando ave_ eccede il valore maxthresh_, a partire dal valore 1/linterm_.
4.1.7. CBQ (Class Based Queueing)
Questo tipo di gestione della coda è basato sulle classi di traffico, cioè esso darà maggiori risorse
alle classi di traffico a più alta priorità. La priorità la si setta al livello sorgente come si vedrà più
avanti.
Metodi:
•
$cbq insert <classe1>: inserisce la classe di traffico classe1 nella gestione del relativo link
CBQ;
•
$cbq bind <classe1> <id1> [<id2>]: associa la classe di traffico classe1 ai pacchetti che hanno
un ID pari a id1 o che hanno ID compreso nel range [id1, id2];
•
$cbq algorithm <alg>: seleziona un algoritmo interno del CBQ.
•
ancestor-only;
•
top-level;
•
formal.
L’oggetto CBQ, a sua volta, ha due discendenti:
12
•
CBQ/WRR: questa sottoclasse implementa una schedulazione di tipo weighted round-robin tra
le varie classi dello stesso livello di priorità.
Parametro:
maxpkt_: (default: ) la massima dimensione di un pacchetto in bytes; serve a calcolare la
massima allocazione di banda.
•
CBQ/PRR: questa sottoclasse implementa una schedulazione di tipo packet-by-packet roundrobin tra le varie classi dello stesso livello di priorità.
Le classi di traffico vengono definite tramite gli oggetti classe-CBQ.
Metodi della classe-CBQ:
•
$classcbq setparams <parent> <okborrow> <allot> <maxidle> <prio> <level>: serve ad
impostare i parametri fondamentali della classi di traffico CBQ predefinita;
•
$classcbq parent <cbqcl|none>: specifica un parente della classe di traffico predefinita; se si
specifica none, allora la classe di traffico è di tipo root, cioè senza antenati;
•
$classcbq newallot <a>: specifica l’allocazione del link per la classe di traffico predefinita,
a∈[0, 1];
•
$classcbq install-queue <q>: installa un oggetto Queue nel link CBQ. Quando un oggetto CBQ
viene creato, esso inizialmente non contiene nessuna coda.
Parametri della classe-CBQ:
•
okborrow_: (default: ) valore booleano che indica se la classe di traffico specificata ha il
permesso di farsi prestare banda dalle classi parente;
•
allot_: (default: ) massima frazione di banda del link allocata per la classe di traffico specificata,
deve essere un numero reale compreso tra 0 ed 1;
•
maxidle_: (default: ) tempo massimo di attesa in coda per i pacchetti della classe di traffico
predefinita. E’ possibile assegnare il valore auto per la decisione automatica di tale tempo;
•
priority_: (default: ) livello di priorità per la classe di traffico, rispetto alle altre classi. Il range
di valori va da 0 (livello più alto) a 10 (livello più basso). Più di una classe può avere lo stesso
livello di priorità;
•
level_: (default: ) livello di una classe di traffico nell’albero della divisione di banda. I nodi
foglia sono considerati al livello 1, i loro parenti al livello 2, ecc.;
•
extradelay_: (default: ) aggiunge il ritardo specificato alla classe di traffico che si vuole
ulteriormente ritardare.
Quando creiamo un oggetto coda tramite le istruzioni simplex-link o duplex-link, i parametri su
elencati contengono i valori di default definiti dallo sviluppatore della classe, per modificare tali
parametri esistono due metodologie. La prima è quello più usuale, in cui una volta istanziato il link
13
‘mio_link’, che supponiamo essere di tipo RED, andiamo a modificare, ad esempio, il parametro
thresh_:
$mio_link set thresh_ <val>
Il secondo metodo è meno ortodosso, poiché consiste nel modificare i parametri del generico
oggetto coda, per es., per lo stesso oggetto RED si scrive:
Queue/RED set thresh_ <val>
Questa istruzione non sortisce effetti fino a quando non si crea un nuovo oggetto coda, che sarà una
copia del generico oggetto coda. In definitiva, se si vogliono creare più oggetti coda dello stesso
tipo e tutti con le stesse caratteristiche, è conveniente andare a modificare i parametri di default che
ci interessano e successivamente creare i vari link.
Per leggere un parametro (per es. lo stesso parametro thresh_ del RED) si deve seguire la seguente
sintassi:
set minth [mio_link set thresh_]
14
5. Livello di Trasporto – Oggetti Agent
La classe Agent implementa un gran numero di protocolli di trasporto, il loro numero comunque è
in continua crescita, man mano che escono nuove versioni dell’ns.
La classe Agent è la classe generale da cui discendono i vari protocolli di trasporto, essa contiene il
seguente set di parametri:
•
addr_: (default: 0) indirizzo del nodo su cui risiede l’Agent;
•
dst_: (default: 0) indirizzo del nodo di destinazione;
•
size_: dimensione dei pacchetti da spedire in bytes;
•
type_: descrive il tipo di pacchetto a seconda del protocollo;
•
fid_: (default: 0) identificatore di flusso IP;
•
prio_: (default: 0) livello di priorità IP;
•
flags_: (default: 0) flag di pacchetto;
•
defttl_: valore di default del ttl IP.
Tali parametri vengono scritti nell’header di ogni pacchetto inviato.
Di seguito viene riportata la lista di tutti i protocolli di trasporto supportati in ns:
5.1.1. Trasmettitori TCP
•
TCP: trasmittente TCP versione “Tahoe”;
•
TCP/Reno: trasmittente TCP versione “Reno”;
•
TCP/NewReno: trasmittente TCP versione “NewReno”;
•
TCP/Sack1: trasmittente TCP versione “Sack”;
•
TCP/Fack: trasmittente TCP versione “Fack”;
•
TCP/Vegas: trasmittente TCP versione “Vegas”;
5.1.2. Ricevitori TCP
•
TCPSink: ricevitore TCP, non usato nel caso di FullTcp;
5.1.3. Altri protocolli
UDP, RAP, TFRC, RTP, RTCP, IVS, CtrMcast, Message, SRM, rtProto/DV, Tap,
LossMonitor, Null.
Per creare un oggetto Agent qualsiasi (es. TCP) occorre eseguire:
set mio_agent [new Agent/TCP]
15
5.1.4. Metodi della classe Simulator
•
attach-agent <nodo> <agent>: attacca <nodo> ad <agent> precedentemente creati;
•
simplex-connect <src> <dst>: instaura una connessione unidirezionale tra gli agent <src> e
<dst>, esso semplicemente imposta l’indirizzo di destinazione e la porta di destinazione di
<src> e di <dst>;
•
connect <src> <dst>: instaura una connessione tra gli agent <src> e <dst>, esso consiste in
una doppia chiamata a simplex-connect con i parametri scambiati;
•
create-connection <srctype> <src> <dsttype> <dst> <pktclass>: questa è una istruzione
composta che crea un agent di tipo <srctype> e lo associa a <src> (attach-agent), un secondo
agent di tipo <dsttype> e lo associa a <dst>; infine esegue la connect tra <src> e <dst>.
Valore restituito: handle dell’agente <src>;
•
create-connection-list <srctype> <src> <dsttype> <dst> <pktclass>: questa istruzione è
molto simile alla precedente, solo che invece di restituire solo l’handle all’agente sorgente,
restituisce una lista di agenti sorgente e destinazione.
5.1.5. Metodi della classe Agent
•
port: restituisce il numero di porta a cui è attaccato l’agent;
•
dst-port: restituisce il numero di porta della destinazione contenuto nella variabile dst_port_;
•
attach-app <application>: attacca l’applicazione specificata al nostro agent.
Di seguito vengono riportate tutte le varie sottoclassi della classe Agent.
5.2. Protocolli TCP
Esistono due classi di protocolli TCP:
•
quelle che effettuano connessioni unidirezionali, cioè un trasmettitore che invia pacchetti dati
ed un ricevitore che si limita ad inviare pacchetti ACK;
•
quelle che effettuano connessioni bidirezionali, in cui ambedue gli agenti sono in grado di
trasmettere ed inviare ACK.
I primi ad essere stati implementati in ns sono quelli che effettuano le connessioni unidirezionali,
cioè si è preferito implementare separatamente, un agent che fungesse solo da trasmettitore, ed un
agent che fungesse solo da ricevitore, anziché implementare un unico agent che supportasse
ambedue le funzionalità. Ciò è stato fatto al fine di snellire il codice di ogni singolo agent e quindi
di rendere le simulazioni più veloci.
Il TCP non fa altro che ricevere segmenti dati da un’applicazione di livello superiore, e di
ritrasmetterli, secondo la propria modalità, in rete.
16
Parametri di configurazione
•
window_: (default: 20) limite superiore della finestra di congestione espressa in pacchetti.
Questo parametro rappresenta virtualmente la advertised window che il ricevente TCP invia al
trasmittente; nel mondo reale questo parametro viene aggiornato automaticamente, invece in ns
ciò non avviene per cui occorre impostare manualmente tale parametro.
•
maxcwnd_: (default: 0) se diverso da 0 rappresenta il massimo valore in pacchetti della
finestra di congestione, se vale 0 tale limite non esiste.
•
windowInit_: (default: 1) dimensione iniziale della finestra di congestione per la fase di slowstart.
•
windowOption_: (default: 1) stabilisce l’algoritmo usato per gestire la finestra di congestione;
l’algoritmo 1 è lo standard.
•
windowConstant_: (default: 4) viene usato sol se windowOption_ è diverso da 1.
•
windowThresh_: (default: 0.002) costante utilizzata nel calcolo della finestra media awnd_.
•
overhead_: (default: 0) ritardo casuale medio (in secondi) aggiunto tra una trasmissione e la
successiva. Se vale 0 non viene aggiunto nessun ritardo. Questo parametro ha effetti solo nella
versione del TCP Tahoe, ed è stato aggiunto solo per evitare, in maniera artificiosa, gli effetti di
fase nel caso di più sorgenti che trasmettono contemporaneamente.
•
ecn_: (default: false) se vale true attiva il riconoscimento del bit Explicit Congestion
Notification (ECN) presente nei pacchetti.
•
packetSize_: (default: 1000) la dimensione in bytes dei pacchetti trasmessi.
•
bugFix_: (default: true) elimina un bug rilevato quando si verificavano delle fast-retransmit
multiple dovute a pacchetti scartati in una singola finestra. Questo parametro può quindi essere
considerato irrilevante.
•
slow_start_restart_: (default: true) decide se ripartire da una fase di slow-start dopo una fase
di idle.
•
tcpTick_: (default: 0.1) granulosità del clock in secondi, che scandisce lo scorrere del tempo in
un qualsiasi sistema operativo. L’ns emula tale clock, che in realtà varia da un sistema
operativo all’altro, con un clock virtuale, per dare la possibilità al ricercatore di simulare il
comportamento del protocollo al variare del sistema operativo in cui esso deve agire. Questo
parametro ha l’importante effetto di determinare la precisione con cui viene valutato il roundtrip-time. Il valore di default non è comunque un valore standard, e quindi deve essere
modificato ad hoc.
•
maxrto_: (default: 64) valore massimo del timeout in secondi.
17
•
maxburst_: (default: 0) se diverso da 0, rappresenta il massimo numero di pacchetti che la
sorgente può spedire in risposta ad un singolo ACK.
Di tutti questi parametri, quelli ovviamente più importanti (cioè quelli che solitamente si ha il
bisogno di modificare) sono: window_ e packetSize_, es.:
$mio_agent set window_ <val>
Variabili di stato
•
dupacks_: numero di ACK duplicati rilevati.
•
seqno_: ultimo numero di sequenza dei dati trasmessi.
•
t_seqno_: numero di sequenza dell’ultimo pacchetto dati trasmesso.
•
ack_: ultimo numero di sequenza rilevato negli ACK;
•
cwnd_: valore attuale della finestra di congestione in pacchetti.
•
awnd_: valore attuale della finestra di congestione media, essa è una versione filtrata in
modalità passa-basso della cwnd_.
•
ssthresh_: valore attuale della soglia di slow-start.
•
rtt_: valore attuale del round-trip time in secondi.
•
srtt_: stima del round-trip time.
•
rttvar_: stima della deviazione media del round-trip time.
•
backoff_: fattore di back-off del round-trip time.
•
maxseq_: massimo numero di sequenza spedito.
Di seguito vengono riportati i protocolli supportati da ns dal più vecchio (Tahoe) al più recente.
TCP
Questa sottoclasse è stata la prima ad essere stata sviluppata, ed in particolare essa implementa la
versione di TCP detta Tahoe.
TCP/Reno
Il TCP Reno è molto simile al Tahoe, eccetto il fatto che esso, in più, implementa il fast recovery.
TCP/NewReno
Questa versione presenta una miglioria rispetto alla versione Reno, che riguarda la correzione del
difetto di quest’ultimo di bloccarsi in alcuni casi particolari.
TCP/Sack1
Versione “Selective ACK” che implementa il “Selective repeat”.
TCP/Fack
Versione “Forward ACK”, è una modifica del TCP Sack.
18
TCP/Vegas
Versione “Vegas” con un accurato controllo delle perdite.
5.2.1. Ricevitori TCP
Abbiamo detto che per i protocolli a connessione unidirezionale occorrono dei protocolli in
ricezione che si limitino esclusivamente ad inviare pacchetti ACK, ecco quindi che vengono di
seguito illustrati i protocolli TCP di ricezione da abbinare ai protocolli di trasmissione.
TCPSink
E’ una sottoclasse della classe Agent, che si occupa esclusivamente di inviare pacchetti di ACK ai
trasmettitori TCP. In particolare, un oggetto TCPSink genera un ACK per ogni pacchetto ricevuto.
Parametri di configurazione
•
packetSize_: (default: 40) dimensione in bytes del pacchetto di ACK.
TCPSink/DelAck
E’ una sottoclasse della classe TCPSink che simula un ricevitore TCP che invia meno di un ACK
per ogni pacchetto dati ricevuto, cioè gli stessi ACK vengono inviati con un ritardo pari a interval_.
Il protocollo agisce in maniera da ritardare gli ACK se i relativi pacchetti dati sono in ordine di
sequenza, per i pacchetti fuori ordine di sequenza, invece, gli ACK vengono generati
immediatamente.
Parametri di configurazione
•
interval_: (default: 0.1) ritardo in secondi tra l’invio di un ACK ed il successivo.
TCPSink/Sack1
Sotto classe della classe TCPSink utilizzabile quando si utilizza un trasmettitore di tipo SACK. Essa
invia un certo numero maxSackBlocks_ di blocchi di informazione di tipo SACK.
Parametri di configurazione
•
maxSackBlocks_: (default: 3) numero di blocchi di informazione SACK da inviare in un unico
ACK.
TCPSink/Sack1/DelAck
Sotto classe della classe Sack1 che implementa gli ACK ritardati analogamente a quanto già visto
sopra.
Es.:
set sorgente [new Agent/TCP/Reno]
set ricevente [new Agent/TCPSink]
19
$ns connect $sorgente $ricevente
5.2.2. Connessioni bidirezionali
TCP/FullTcp
Sottoclasse del TCP in grado di effettuare connessioni bidirezionali. La versione implementata è la
Reno. A differenza dei protocolli a connessione unidirezionale, essa effettua la creazione e
l’abbattimento di una connessione tramite lo scambio di messaggi SYN/FIN con il meccanismo 3way handshake.
Sia il trasmittente che il ricevente devono essere dichiarati nella stessa maniera.
Parametri di configurazione
•
segsperack_: (default: 1) segmenti da ricevere prima di generare un ACK;
•
segsize_: (default: 536) dimensione del segmento in bytes;
•
tcprexmtthresh_: (default: 3) numero di ACK duplicati da ricevere prima di far scattare la fase
di fast retransmit;
•
iss_: (default: 0) numero di sequenza iniziale da spedire;
•
nodelay_: (default: false) disabilita l’algoritmo di Nagle dalla parte del trasmittente;
•
data_on_syn_: (default: false) spedisce dati anche nei SYN;
•
dupseg_fix_: (default: true) evita la fase di fast retransmit dovuta ad ACK duplicati;
•
dupack_reset_: (default: false) ;
•
interval_: (default: 0.1) ;
5.2.3. Altri aspetti del TCP
Nelle simulazioni non vengono spediti dei dati reali, ma soltanto dei pacchetti con una certa
dimensione, dove le uniche informazioni significative sono contenute nell’header.
Header
La struttura dell’header di un pacchetto non è complessa come quella delle reali comunicazioni
TCP, ma contiene soltanto i seguenti campi:
•
ts_: (time stamp) tempo di partenza del pacchetto dalla sorgente;
•
ts_echo_: valido per gli ACK, esso rappresenta il campo time stamp del pacchetto associato
all’ACK;
•
seqno_: numero di sequenza per il pacchetto, sia dati che ACK;
•
reason_: ;
20
5.3. Agent/Null
Questo è una sottoclasse della classe Agent, che però è del tutto inattiva, e quindi può essere
utilizzata solo come ricevitore di pacchetti, ma solo per le trasmissioni non ACK-clocked, in cui la
sorgente dei dati non richiede nessuna collaborazione al destinatario (come l’UDP).
Variabili si stato
•
sport_: ;
•
dport_: ;
5.4. Agent/LossMonitor
Analogamente all’Agent/Null, anche il LossMonitor è un Agent di tipo passivo da usare come sink
dei pacchetti per sorgenti non ACK-clocked, con la particolarità che esso tiene conto delle
statistiche sul traffico ricevuto.
Variabili di stato
•
nlost_: numero di pacchetti persi;
•
npkts_: numero di pacchetti ricevuti;
•
bytes_: numero di bytes ricevuti;
•
lastPktTime_: tempo in cui è stato ricevuto l’ultimo pacchetto;
•
expected_: il numero di sequenza atteso per il prossimo pacchetto.
Metodi
•
clear: resetta il numero di sequenza atteso expected_ a –1.
5.5. Protocollo UDP
Un oggetto della classe UDP si limita a ricevere dati da una applicazione di livello superiore ed a
ritrasmetterli in rete con una ben determinata segmentazione. I pacchetti inviati contengono un
numero di sequenza monotonicamente crescente ed un time stamp. Questo protocollo implementa
un sistema di trasmissione di tipo datagram (non ACK-clocked), quindi come ricevente può essere
utilizzato un Agent di tipo Null
Parametri di configurazione
•
packetSize_: (default: 1000) dimensione del pacchetto in bytes.
Es.:
set sorgente [new Agent/UDP]
set ricevente [new Agent/Null]
21
$ns connect $sorgente $ricevente
5.6. Protocollo RAP
RAP sta per Rate Adaptation Protocol ed è un protocollo TCP-friendly adatto per lo streaming
audio-video in real-time. Esso tenta di emulare il funzionamento di una generica sorgente TCP al
variare dello stato di congestione della rete, e quindi cerca di trasmettere circa allo stesso rate. A
differenza del TCP e dell’UDP, al RAP non possono essere attaccate delle applicazioni di livello
superiore, poiché esso stesso implementa internamente una pseudo-applicazione che trasmette tanti
pacchetti quanti ne è in grado di trasmettere il protocollo man mano che la simulazione evolve.
variabili di stato
•
seqno_: (valore iniziale: 0) numero di sequenza dei pacchetti;
•
ipg_: (valore iniziale: 2) inter packet gap, ovvero intervallo di tempo che intercorre nella
spedizione tra un pacchetto ed il successivo in secondi. Il suo inverso rappresenta il rate di
trasmissione della sorgente in pacchetti al secondo;
•
srtt_: (valore iniziale: 2) stima del round trip time (RTT) in secondi;
•
variance_: (valore iniziale: 0) stima della varianza del RTT;
•
timeout_: (valore iniziale: 2) valore di scadenza del time out in secondi;
Parametri di configurazione
•
packetSize_: (default: 512) dimensione del pacchetto in bytes;
•
beta_: (default: 0.5) fattore moltiplicativo per il rate di trasmissione quando viene rilevata una
perdita od un time out;
•
alpha_: (default: 1) fattore correttivo nell’algoritmo dell’incremento del rate; più alpha_ è
grande, maggiore è l’incremento del rate;
•
delta_: (default: 0.5) peso dato alla variazione istantanea del RTT nella valutazione del RTTmedio (srtt_), influisce anche nel calcolo della varianza;
•
mu_: (default: 1.2) peso dato alla variabile srtt_ nel calcolo di timeout_;
•
phi_: (default: 4) peso dato alla variabile variance_ nel calcolo di timeout_;
•
overhead:_ (default: 0) ritardo medio aggiunto alla trasmissione dei pacchetti;
•
useFineGrain_: (default: false) switch che consente di abilitare la modalità fine grain
adaptation;
•
kfrtt_: (default: 0.9) coefficiente utilizzato nel calcolo del RTT di breve termine, valido solo se
useFineGrain_ = true;
22
•
kxrtt_: (default: 0.01) coefficiente utilizzato nel calcolo del RTT di lungo termine, valido solo
se useFineGrain_ = true;
metodi
•
start: avvia la pseudo applicazione;
•
stop: termina la pseudo applicazione.
Es.:
set sorgente [new Agent/RAP]
set ricevente [new Agent/RAP]
$ns connect $sorgente $ricevente
$ns at <ti> “$sorgente start”
$ns at <tf> “$sorgente stop”
5.7. Protocollo TFRC
TFRC sta per TCP Friendly Rate Control ed è un protocollo TCP-friendly adatto per lo streaming
audio-video in real-time. Esso tenta di emulare il funzionamento di una generica sorgente TCP
calcolandone analiticamente il throughput in base alle condizioni di rete, e quindi (come per il RAP)
cerca di trasmettere circa allo stesso rate. Anche per il TFRC non possono essere attaccate delle
applicazioni di livello superiore, poiché esso stesso implementa internamente una pseudoapplicazione che trasmette tanti pacchetti quanti ne è in grado di trasmettere il protocollo man mano
che la simulazione evolve.
Essendo le funzioni svolte dal ricevitore più snelle di quelle del trasmettitore, è stato implementato
l’Agent/TFRCSink (analogamente a quanto già visto per il TCP).
variabili di stato
•
ndatapack_: (valore iniziale: 0) numero di pacchetti spediti;
Parametri di configurazione
•
packetSize_: (default: 1000) dimensione del pacchetto in bytes;
•
df_: (default: 0.95) fattore di decay per una stima accurata dell’RTT;
•
tcp_tick_: (default: 0.1) granulosità del clock in secondi, che scandisce lo scorrere del tempo in
un qualsiasi sistema operativo (vedi TCP).
•
overhead:_ (default: 0) ritardo medio aggiunto alla trasmissione dei pacchetti;
•
ssmult_: (default: 2) fattore moltiplicativo dell’incremento del rate di trasmissione durante la
fase di slow-start;
23
•
bval_: (default: 1) corrisponde alla costante B nella formula per la determinazione del rate del
TCP;
•
ca_: (default: 1) attiva l’uso della radice dell’RTT nella fase di congestion avoidance;
metodi
•
start: avvia la pseudo applicazione;
•
stop: termina la pseudo applicazione.
TFRCSink
E’ una sottoclasse della classe Agent, che si occupa esclusivamente di inviare pacchetti di ACK ai
trasmettitori TFRC.
Parametri di configurazione
•
packetSize_: (default: 40) dimensione in bytes del pacchetto di ACK.
Es.:
set sorgente [new Agent/TFRC]
set ricevente [new Agent/TFRCSink]
$ns connect $sorgente $ricevente
$ns at <ti> “$sorgente start”
$ns at <tf> “$sorgente stop”
24
6. Livello applicativo
Il livello applicativo è rappresentato dalla classe astratta Application, ed i vari tipi di applicazione
supportati in ns sono implementati in sottoclassi della stessa classe Application.
Esistono due tipi base di applicazione: generatori di traffico ed applicazioni simulate.
Per creare un oggetto Application qualsiasi (es. CBR) occorre eseguire:
set mia_app [new Application/Traffic/CBR]
6.1.1. Metodi della classe Application
•
attach-agent <agent>: attacca <agent> alla nostra applicazione;
•
start: avvia la applicazione;
•
stop: termina la applicazione;
Es.:
$mia_app attach-agent $mio_agent
o, equivalentemente:
set mia_app [$mio_agent attach-app Traffic/CBR]
dove il metodo attach-app appartiene alla classe Agent.
6.2. Generatori di traffico
La classe TrafficGenerator (in Otcl viene mappata col nome Traffic) è una sottoclasse della classe
Application, anche essa è una classe astratta, da cui discendono quattro applicazioni operative.
Queste quattro applicazioni possono essere agganciate al protocollo di trasporto UDP.
6.2.1. Exponetial On/Off (Application/Traffic/Exponential)
Implementa una sorgente on/off con distribuzione esponenziale. Nel periodo ‘on’ i pacchetti
vengono spediti con un rate fissato, mentre nel periodo ‘off’ non viene spedito alcun pacchetto. Le
durate dei periodi ‘on’ e ‘off’ vengono sono variabili aleatorie con distribuzione esponenziale.
Parametri di configurazione
•
packetSize_: (default: 512) dimensione del pacchetto in bytes;
•
burst_time_: (default: ) durata media in secondi del periodo ‘on’ del generatore;
•
idle_time_: (default: ) durata media in secondi del periodo ‘off’ del generatore;
•
rate_: (default: ) rate di trasmissione adottato durante i periodi di ‘on’ in bit/s.
25
6.2.2. Pareto On/Off (Application/Traffic/Pareto)
Implementa una sorgente on/off con distribuzione paretiana. Il funzionamento di questa sorgente di
traffico è identico a quello esponenziale appena descritto, con la differenza consiste proprio nel tipo
di distribuzione casuale che caratterizza i periodi di ‘on ‘ e ‘off’.
Parametri di configurazione
•
packetSize_: (default: 512) dimensione del pacchetto in bytes;
•
burst_time_: (default: ) durata media in secondi del periodo ‘on’ del generatore;
•
idle_time_: (default: ) durata media in secondi del periodo ‘off’ del generatore;
•
rate_: (default: ) rate di trasmissione adottato durante i periodi di ‘on’ in bit/s;
•
shape_: (default: 1) parametro ‘shape’ che influisce sulla distribuzione paretiana.
6.2.3. CBR (Application/Traffic/CBR)
Generatore di traffico di tipo constant-bit-rate.
Parametri di configurazione
•
packetSize_: (default: 512) dimensione del pacchetto in bytes;
•
rate_: (default: ) rate di trasmissione in bit/s;
•
interval_: (default: ) intervallo di tempo in secondi tra la trasmissione di un pacchetto ed il
successivo, quindi esso equivale all’inverso del rate espresso in pacchetti/s.
•
random_: (default: 0) se diverso da 0 introduce una variabilità casuale del tempo di spedizione
tra un pacchetto ed il successivo, pari a ±50% di interval_;
•
maxpkts_: (default: 228 ) numero massimo di pacchetti da spedire. Per default vi è un numero
altissimo che, praticamente corrisponde ad una trasmissione di dati infinita.
I parametri rate_ ed interval_ sono mutuamente esclusivi, nel senso che l’utente deve settare solo
uno dei due (e non entrambi), in quanto l’altro si configurerà automaticamente di conseguenza.
6.2.4. Traffic Trace (Application/Traffic/Trace)
Genera traffico in base ai dati presenti in un file di ‘trace’ (generato dall’utente). Ogni record del
file di trace consiste di due campi da 32-bit: il primo campo deve contenere il tempo (in
microsecondi) che il generatore deve attendere prima di trasmettere il pacchetto successivo; il
secondo campo deve contenere la lunghezza (in bytes) del pacchetto successivo.
Non ci sono parametri di configurazione per questa classe di traffico.
26
6.3. Applicazioni simulate
Esistono due tipi di applicazioni simulate: FTP e Telnet; esse sono state create esclusivamente per
usufruire del servizio di trasporto TCP (poiché entrambe le applicazioni necessitano della
trasmissione affidabile dei dati).
6.3.1. FTP (Application/FTP)
Applicazione di tipo File Trasfer Protocol per la trasmissione di blocchi di dati.
metodi
•
produce n: setta il contatore dei pacchetti da spedire ad ‘n’;
•
producemore n: incrementa il contatore dei pacchetti da spedire di ‘n’;
•
send n: simile a produce, ma spedisce ‘n’ bytes anziché pacchetti.
Parametri di configurazione
•
maxpkts_: (default: 0) numero massimo di pacchetti generati dall’applicazione. Se vale 0 il
numero di pacchetti generato sarà indefinito.
6.3.2. Telnet (Application/Telnet)
Applicazione di tipo Telnet, i pacchetti possono essere generati in due modi, a seconda del valore
del parametro interval_.
Parametri di configurazione
•
interval_: (default: 0) tempo medio, espresso in secondi, che intercorre tra la generazione di un
pacchetto ed il successivo ( inte- packet-gap).
Se interval_ è diverso da 0 allora l’inter-packet-gap viene scelto da una distribuzione esponenziale
con valore medio pari ad interval_. Se, invece, interval_ vale 0, allora l’inter-packet-gap viene
scelto in accordo alla distribuzione “tcplib” contenuta nel file tcplib-telnet.cc
Es.:
set app [new Application/Traffic/CBR]
$app set rate_ <val>
set sorgente [new Agent/UDP]
$app attach-agent $sorgente
set ricevente [new Agent/Null]
$ns connect $sorgente $ricevente
$ns at <ti> “$app start”
$ns at <tf> “$app stop”
27
7. Rilevazione dei dati
7.1. Oggetti QueueMonitor
Gli oggetti della classe QueueMonitor sono usati per rilevare la quantità di dati che vengono
inoltrati o scartati nella coda di un determinato link.
Per creare un monitor si usa:
$ns monitor-queue <nodo1> <nodo2> <optional: qtrace> <optional: sampleinterval>
viene creato un monitor per monitorare la coda sul <nodo1> per tutti i pacchetti che si dirigono dal
<nodo1> al <nodo2>.
es.:
set mio_monitor [$ns monitor-queue $n1 $n2]
questa istruzione istanzia un monitor nella variabile ‘mio_monitor’, il parametro opzionale
sampleinterval vale 0.1 per default.
N.B. In realtà occorre specificare anche il parametro qtrace, per cui, anche se non se ne fa uso,
occorre inserire anche una parola qualunque.
es.:
set mio_monitor [$ns monitor-queue $n1 $n2 mio_qtrace]
dove al posto di mio_qtrace si può mettere una parola qualunque.
Durante la simulazione, il monitor, mette a disposizione in lettura le seguenti variabili di stato:
•
size_: lunghezza della coda istantanea in bytes;
•
pkts_: lunghezza della coda istantanea in pacchetti;
•
parrivals_: totale dei pacchetti che giungono al relativo link;
•
barrivals_: totale dei pacchetti che giungono al relativo link espresso in bytes;
•
pdepartures_: totale dei pacchetti che vengono spediti nel link;
•
bdepartures_: totale dei pacchetti che vengono spediti nel link espresso in bytes;
•
pdrops_: totale dei pacchetti scartati nel link (solitamente dal meccanismo di gestione della
coda);
•
bdrops_: totale dei pacchetti scartati nel link espresso in bytes;
•
bytesInt_: oggetto Integrator che calcola l’integrale della dimensione della coda in bytes. Il
valore corrente di questo integrale è contenuto nella variabile sum_ dell’oggetto bytesInt_;
•
pktsInt_: oggetto Integrator che calcola l’integrale della dimensione della coda in pacchetti. Il
valore corrente di questo integrale è contenuto nella variabile sum_ dell’oggetto pktsInt_.
28
Se per esempio vogliamo leggere il valore della coda in pacchetti dobbiamo fare:
set coda [$mio_monitor set pkts_]
tra le variabili su elencate, vale la seguente relazione:
parrivals_ = pdepartures_ + pdrops_
Lo stesso vale ovviamente anche per le stesse variabili che espresse in bytes (col prefisso ‘b’
anziché ‘p’).
7.2. Oggetti FlowMon
L’oggetto QueueMonitor da una rilevazione globale dei pacchetti inoltrati/scartati, se invece siamo
interessati a distinguere tali dati per-flusso, dobbiamo utilizzare un oggetto FlowMon cioè monitor
di flusso.
Per distinguere un flusso dall’altro si può utilizzare il fid (flow identifier) definito nelle sorgenti
(fid_ degli oggetti Agent)
Possiamo allora andare a stanziare un monitor che distingue i flussi con la seguente sintassi:
set mio_flowmon [$ns makeflowmon Fid]
la variabile mio_flowmon rappresenterà un monitor di flusso, che dovremo andare ad attaccare ad
una determinata coda nel seguente modo:
set mio_link [$ns link <nodo1> <nodo2>]
$ns attach-fmon $mio_link $mio_flowmon
Prima di andare a leggere i dati occorre inserire un classificatore nell’oggetto flowmonitor, es:
set flowclassifier [$mio_flowmon classifier]
a questo punto siamo in grado di selezionare il fid che ci interessa monitorare con:
set flow [$flowclassifier lookup auto 0 0 <fid>]
e finalmente possiamo leggere tutti i dati che ci interessano con:
set num_pack [$flow set pdepartures_]
ovviamente oltre a pdepartures_ possiamo leggere tutte le altre variabili elencate nel paragrafo
precedente.
Occorre perciò definire un fid diverso per ogni sorgente, nel caso in cui siamo interessati alle
singole statistiche. Se, invece, siamo interessati a statistiche aggregate, cioè dei pacchetti
inoltrati/scartati da un insieme di flussi, possiamo assegnare il medesimo fid ad un certo numero di
sorgenti. In questa maniera, in fase di lettura, otterremo la somma, per esempio, dei pacchetti
scartati per un determinato gruppo di flussi.
29
N.B. la lettura delle statistiche non può essere fatta prima che le sorgenti interessate abbiano spedito
almeno un pacchetto, altrimenti il simulatore si fermerà e darà un messaggio di errore. Quindi, in
fase di schedulazione, bisogna accertarsi che non vengano effettuate letture, in istanti di tempo
precedenti all’invio del primo pacchetto da parte delle sorgenti da monitorare.
7.3. Lettura delle variabili di stato
In qualunque momento della simulazione è possibile leggere le variabili di stato delle entità
coinvolte (Agent, Application, Queue, ecc.). Una volta creato un Agent, ad esempio:
set mio_agent [new Agent/TCP]
mentre la simulazione gira è possibile schedulare istruzioni del tipo:
set val [$mio_agent set agent_var]
che non fa altro che leggere il valore della variabile agent_var presente all’interno dell’agent
mio_agent e conservarlo in val.
es.:
set val [$tcp_agent set rtt_]
30
8. Nozioni sul linguaggio TCL
E’ un linguaggio script molto potente, simile al C o al delphi.
Per effettuare una qualsiasi inizializzazione di variabile occorre fare:
set <var> <val>
per fare una qualunque operazione matematica occorre usare expr dentro le parentesi quadre [],es.:
set x [expr $y+sqrt($z)/cos($y)]
non si possono usare le parentesi tonde per annidare le operazioni, ma bisogna utilizzare altri
blocchi [expr] annidati.
Per valutare una variabile bisogna anteporre il simbolo $ (vedi espressione precedente). Ci sono
alcuni casi in cui non bisogna usare il $ prima di una variabile:
•
subito dopo l’istruzione set;
•
nella lista dei parametri di ingresso di una procedura
Una variabile può facilmente diventare un vettore semplicemente indicandone l’indice, es.:
set y(2) <val>
per inserire dei commenti, si utilizza il #, tutto ciò che si trova dopo di esso, nella stessa linea, non
viene considerato. Il # ha la validità di una linea.
Per un buon debugging del vostro script, può essere utile stampare nello schermo i valori delle
variabili che vi interessano, a tal proposito si usa l’istruzione puts, es:
puts $mia_var
per stampare una semplice stringa di testo si fa:
puts ciao
oppure:
puts “ciao”
scrive “ciao” nello schermo (prompt del DOS).
Per scrivere più cose nella stessa riga si devono usare obbligatoriamente le virgolette, es.:
puts “rate: $mio_rate tempo: $mio_tempo”
tutti i termini devono essere separati da uno spazio. Per distinguere le variabili dalle stringhe di
testo si deve anteporre il simbolo ‘$’.
8.1.1. Gestione dei Files
Per aprire un file di testo bisogna fare:
set mio_file [open nome_file w]
31
in questo caso il file è stato aperto in scrittura (valgono le stesse regole del C), ma è anche possibile
aprirlo in modalità append con a al posto di w.
Per scrivere dati in un file (di testo), occorre usare l’istruzione puts. Ad esempio se vogliamo
scrivere nel file un valore numerico contenuto nella variabile mia_var, si deve fare:
puts $mio_file $mia_var
in questo modo, la variabile numerica mia_var sarà convertita in testo e scritta nel file, in modo da
poter essere utilizzabile sia da Matlab che da Excel. Per il resto vale la stessa sintassi di puts
descritta in precedenza.
Per chiudere un file occorre fare:
close $mio_file
8.1.2. FOR
Sintassi:
for {set i 0} {condizione} {incr i} {
<blocco di istruzioni>
}
un esempio di condizione è: “$i < <top>”.
al posto di “incr i”, potremmo alternativamente mettere “set i [expr $i+1]” oppure
$i+$tick]” dove tick è un numero reale.
8.1.3. IF
Sintassi:
if {condizione} {
<blocco di istruzioni>
}
else {
<blocco di istruzioni>
}
else if {condizione} {
<blocco di istruzioni>
}
8.1.4. PROC
Sintassi:
proc mia_proc {parametri in} {
32
“set i [expr
<blocco di istruzioni>
}
i parametri di ingresso sono opzionali e devono essere separati da uno spazio.
Le procedure sono completamente isolate dal resto del codice, per cui qualunque variabile esterna
sarà invisibile. Per rendere visibili le variabili esterne in tutti e due i sensi occorre dichiararle come
global (vedi esempio).
Per chiamare una procedura bisogna scrivere:
mia_proc <parametri>
i parametri devono essere preceduti da un $,e separati tra loro con uno spazio.
8.1.5. Numeri casuali
La generazione di numeri casuali che si sta per descrivere non deriva dal linguaggio TCL nativo,
ma costituisce un arricchimento del simulatore. Per generare numeri casuali occorre innanzitutto
creare una istanza di variabile casuale nel seguente modo:
set mia_random_var [new RandomVariable/Uniform]
dove RandomVariable è la classe astratta da cui discendono i veri oggetti random che possiamo
usare. La più usata è la sottoclasse Uniform, che è in grado di generare numeri casuali con
distribuzione uniforme di probabilità entro un intervallo arbitrario. Tale intervallo può essere
definito mediante le due variabili membro min_ e max_ come segue:
$mia_random_var set min_ <value>
$mia_random_var set max_ <value>
per default essi valgono rispettivamente 0 e 1.
A questo punto è possibile ricavare i valori casuali nel seguente modo:
set rand_val [$mia_random_var value]
Per completezza, vengono di seguito esposte le altre sottoclassi:
•
Pareto. Variabili membro: avg_ (default:1), shape_ (default: 1.2);
•
Exponential. Variabili membro: avg_ (default: 1);
•
HyperExponential. Variabili membro: avg_ (default: 1), cov_ (default: 4);
Per cambiare il seme di generazione dei numeri casuali si deve usare l’istruzione:
ns-random $nuovo_seme
Il seme di default è 1, per cui se lo si vuole cambiare, si deve porre un altro valore intero.
33
8.1.6. Lancio della simulazione
Lo script TCL serve a costruire la topologia della rete da analizzare e a schedulare i vari eventi che
ci interessano, tutto ciò viene elaborato ed immagazzinato in memoria durante il parsing dello
script. Per lanciare effettivamente la simulazione, si deve mettere, alla fine dello script TCL,
l’istruzione:
$ns run
che non fa altro che seguire il calendario di eventi che sono stati precedentemente schedulati.
34
9. Precisione dei risultati
Per garantire che i risultati siano attendibili, è necessario cominciare i rilevamenti dopo che si è
estinto il transitorio di partenza, ad esmpio, quando la coda di un router diventa stabile nel tempo.
Ci si prefissa, ad esempio, di ottenere una precisione dell’1% con una probabilità del 90%;
supponiamo che x0 sia il risultato numerico della simulazione, la precisione suddetta garantisce che
il risultato reale si trova nel 90% dei casi entro un intervallo detto intervallo di confidenza ε pari
all’1% di x0 :
x0 - ε < x0 < x0 + ε
Il simulatore non sa nulla di queste cose, quindi i risultati devono essere gestiti per intero
dall’utente, per cui occorre elaborare uno script simulativo che oltre alla simulazione stessa,
implementi la precisione dei risultati; per l’esattezza occorre implementare l’algoritmo esposto in
fig. 1. In tale grafo di flusso si calcolano a partire dalla seconda simulazione, sia il valore medio che
lo scarto quadratico medio del risultato, in base a questi sarà quindi calcolato l’ε t temporaneo. Il
gruppo di simulazioni finirà solo quando ε t sarà minore di 10-2 che rappresenta l’ε desiderato o
l’intervallo di confidenza desiderato.
Per calcolare l’intervallo di confidenza temporaneo ε t si fa uso dei valori dei percentile tpN che sono
disponibili in forma tabulata.
Un metodo pratico consiste nell’effettuare tante simulazioni tutte in una, per cui, si fa partire la
simulazione, e sia aspetta che il transitorio si estingue, ad esempio quando si stabilizza il valore di
una certa coda all’interno della topologia. Finito il transitorio, si fa partire una prima fase di regime,
al termine della quale otterremo il nostro primo valore (un throughput, un valore di coda media, un
ritardo, ecc.) che conserveremo in un vettore. A questo punto, anziché iniziare una nuova
simulazione, non facciamo altro che continuare quella precedente, lanciando una seconda fase di
regime al fine di ottenere il secondo risultato, che andremo a confrontare col primo, se la precisione
non ci soddisferà, si lancerà una terza fase di regime, e così via.
Questo modo di procedere rimane valido, perché i valori delle variabili della simulazione sono
diversi per ogni regime, e quindi è come se essi venissero originati da condizioni iniziali differenti.
35
ε = 10-2
p = 90%
N= 1
calcola il 1° risulato g1
N = N +1
calcola il l'N-esimo risulato gN
calcola il valore medio
g' = (g1 + g2 + ... + gN) / N
calcola lo scarto quadratico medio
Σ i (gi -g')2
s =
N
calcola intervallo di confidenza
temporaneo
s
ε t = t pN
N-1
no
εt ≤ε ?
si
risultato
g = g' ± ε
fine
Fig.1
36
10. Passaggio dei parametri dal prompt DOS
Quando lanciamo l’ns dalla riga di comando del DOS (es. ns mio_script.tcl <INVIO>), abbiamo la
possibilità di passare al simulatore dei parametri supplementari mediante argc e argv (vedi C++). E’
quindi possibile scrivere una riga del tipo:
ns mio_script.tcl –banda 100000 –coda 40 <INVIO>
per poter passare, ad esempio, due parametri che mi vanno a cambiare il valore di banda di un certo
link e la capacità della coda di un certo buffer all’interno della nostra topologia. Questo metodo è
utile quando devo lanciare diverse simulazioni in cui cambia solo il valore di banda o della capacità
di una coda, senza dover necessariamente modificare il file mio_script.tcl.
Per fare ciò, è necessario programmare lo script di simulazione in modo da definire quanti e quali
parametri si vuole modificare dall’esterno.
Quando lanciamo l’ns dal prompt del DOS, il sistema ,automaticamente, definisce le due variabili
argc e argv nel seguente modo:
•
argc: numero di stringhe presenti nella riga di comando, susseguenti il file tcl;
•
argv: vettore di argc elementi contenente le stringhe presenti nella riga di comando
susseguenti il file tcl.
Es., se digito:
ns mio_script.tcl –banda 100000 –coda 40 –delay 25 <INVIO>
all’interno dello script vi troverete:
argc = 6,
argv = [‘-banda’, ‘100000’, ‘-coda’, ‘40’, ‘-delay’, ‘25’]
Questo metodo di scrivere prima il tag di riconoscimento del parametro da modificare, e poi il
valore da sostituire a quello di default, è quello più largamente diffuso; però non è detto che uno
non possa usare altri tipi di convenzione più consoni alle proprie esigenze.
Ad ogni modo, occorre quindi scrivere delle righe di codice TCL che effettuino il parsing di argv in
modo da riconoscere i propri tag, ed assegnare ai parametri ad essi corrispondenti i valori numerici
messi di seguito. Per es. a ‘banda’ corrisponderà il parametro B1 a cui assegneremo il valore
100000.
Un esempio di parsing di argv è il seguente spezzone di codice TCL:
for {set i 0} {$i < $argc} {incr i} {
set arg [lindex $argv $i]
if {[string range $arg 0 0] != "-"} continue
set name [string range $arg 1 end]
if {$name == "banda"} {
set B1 [lindex $argv [incr i]]
} elseif {$name == "coda"} {
37
set K [lindex $argv [incr i]]
ecc. …………
} else {
puts "ERRORE: Parametro $name sconosciuto!"
exit 1
}
}
dove lindex ritorna la stringa specificata da $i, mentre string range restituisce una sottostringa
specificata dagli indici di carattere tra 0 ed end. In questo modo si è usata la convenzione che tutti i
tag devono essere preceduti dal trattino’-‘.
38
11. Appendice
11.1. NAM
Il NAM (Network AniMator) è un tool che serve a visualizzare l’evoluzione temporale della
simulazione.
L’ns può memorizzare l’evoluzione temporale della simulazione in un file che chiameremo
‘out.nam’, quindi dobbiamo inserire nel nostro script le seguenti istruzioni:
set nf [open out.nam w]
$ns namtrace-all $nf
namtrace-all è un metodo della classe Simulator, e non fa altro che dire al simulatore di conservare
nel file indicato da $nf (out.nam) tutti i dati di cui ha bisogno il NAM, dall’inizio, alla fine della
simulazione. E’ chiaro che la dimensione del file out.nam dipende dalla durata della simulazione,
inoltre essa dipende anche dalle capacità dei link e dal numero di sorgenti.
Per lanciarlo dal prompt del DOS occorre digitare:
nam out.nam
dove si presuppone che i file nam.exe e out.nam siano nella stessa directory
11.2. Esempio di script TCL
#Crea un oggetto simulatore
set ns [new Simulator]
set durata 200
set tick [expr $durata / 100]
set regime [expr 0.4 * $durata]
set packet 100
set BW 200KB
set n 0
set qsum 0
set asum 0
#Definisce colori diversi per i due flussi
$ns color 1 Blue
$ns color 2 Red
#apre il trace file per il NAM
set nf [open out.nam w]
$ns namtrace-all $nf
#procedura chiama alla fine della simulazione
proc finish {} {
global ns
global nf
global rapbw tcpbw durata regime packet BW
global qsum asum n
$ns flush-trace
39
puts "banda da condividere: $BW"
puts "rap BW = [expr [expr $rapbw * $packet] / [expr $durata - $regime]] bytes/s"
puts "tcp BW = [expr [expr $tcpbw * $packet] / [expr $durata - $regime]] bytes/s"
set qmedia [expr $qsum / $n]
puts "valore medio della coda : $qmedia"
set amedia [expr $asum / $n]
puts "valore medio della coda media : $amedia"
#Chiude il trace file
close $nf
exit 0
}
#Crea 4 nodi
set tcps [$ns node]
set tcpd [$ns node]
set red1 [$ns node]
set red2 [$ns node]
$red1 color red
$red2 color red
$red1 shape hexagon
$red2 shape hexagon
$red1 label red-router
$red2 label red-router
set raps [$ns node]
set rapd [$ns node]
#Crea i links tra i nodi
$ns duplex-link $tcps $red1 10Mb 2ms DropTail
$ns duplex-link $red2 $tcpd 10Mb 2ms DropTail
$ns duplex-link $red1 $red2 $BW 20ms RED
$ns duplex-link $raps $red1 10Mb 2ms DropTail
$ns duplex-link $red2 $rapd 10Mb 2ms DropTail
set ftp [new Application/FTP]
#Crea un agente TCP e lo attacca al nodo
set tcp [new Agent/TCP]
$ns attach-agent $tcps $tcp
$tcp set packetSize_ $packet
$tcp set fid_ 1
$ftp attach-agent $tcp
#Crea un agente Null (traffic sink) e lo attacca al nodo
set tcpsink [new Agent/TCPSink]
$ns attach-agent $tcpd $tcpsink
#############################################################
#Crea un agente RAP e lo attacca al nodo
set rap [new Agent/RAP]
$ns attach-agent $raps $rap
$rap set packetSize_ $packet
$rap set beta_ 0.5
$rap set fid_ 2
set rapsink [new Agent/RAP]
$ns attach-agent $rapd $rapsink
#Connette le sorgenti ai riceventi
40
$ns connect $tcp $tcpsink
$ns connect $rap $rapsink
#crea un flow-monitor
proc creaflowmon {} {
global red1 red2
global counter ns nodes rapbw tcpbw
global flowClassifier
set rapbw 0
set tcpbw 0
set counter [$ns makeflowmon Fid]
set bottleneck [$ns link $red1 $red2]
$ns attach-fmon $bottleneck $counter
set flowClassifier [$counter classifier]
}
#segna bw
proc segnapacchetti {} {
global counter rapbw tcpbw
global flowClassifier
set flowrap [$flowClassifier lookup auto 0 0 2]
set rapshare [$flowrap set pdepartures_]
set rapbw [expr $rapshare - $rapbw]
set flowtcp [$flowClassifier lookup auto 0 0 1]
set tcpshare [$flowtcp set pdepartures_]
set tcpbw [expr $tcpshare - $tcpbw]
}
#tiene traccia della coda del bottleneck
set redqc [[$ns link $red1 $red2] queue]
proc segnacoda {} {
global ns red1 red2 redqc
global qsum asum n
#set fc [open fc.out w]
set redqc [[$ns link $red1 $red2] queue]
#$redqc trace curq_
#$redqc attach $fc
set cc [$redqc set curq_]
set qsum [expr $qsum + $cc]
set cc [$redqc set ave_]
set asum [expr $asum + $cc]
set n [expr $n + 1]
}
creaflowmon
#fase di scheduling
$ns at [expr $durata * 0.01] "$ftp start"
$ns at [expr $durata * 0.01] "$rap start"
41
$ns at [expr $durata * 0.97] "$rap stop"
$ns at [expr $durata * 0.99] "$ftp stop"
$ns at $regime "segnapacchetti"
$ns at $durata "segnapacchetti"
for {set i 1} {$i < $durata} {set i [expr $i + $tick]} {
$ns at $i "segnacoda"
}
$ns at $durata "finish"
#lancia la simulazione
$ns run
42