Post on 13-Jun-2015
description
transcript
UNIVERSITÀ DEGLI STUDI DI TRIESTE
FACOLTÀ DI INGEGNERIA
Tesi di Laurea Specialistica in
INGEGNERIA INFORMATICA
PROGETTO E REALIZZAZIONE DI UN
KERNEL LINUX PER IL CONTROLLO
DINAMICO DEGLI STIMATORI DI PERDITA
SEGMENTI IN TCP
Relatore Laureando
Chiar.mo Prof. Alberto Bartoli Myrteza Kertusha
Anno Accademico 2011/2012
1
INDICE
Indice delle figure .............................................................................................................................. 3
Introduzione ....................................................................................................................................... 4
1 Architettura ..................................................................................................................................... 6
1.1 Registrazione RTT e RTO ........................................................................................................... 6
1.1.1 Utilizzo ............................................................................................................................... 7
1.2 Formula aggiornamento dinamico RTO .................................................................................... 8
1.2.1 Utilizzo ............................................................................................................................... 9
1.2.1.1 Gestione formula per calcolo RTO ............................................................................. 9
1.2.1.2 Associazione ‘formula-connessione’ ......................................................................... 9
2 Implementazione .......................................................................................................................... 11
2.1 Registrazione RTT e RTO ......................................................................................................... 11
2.1.1 Contesto kernel ............................................................................................................... 11
2.1.1.1 Kernel built-in .......................................................................................................... 12
2.1.1.2 Modulo kernel ......................................................................................................... 15
2.1.2 Contesto utente ............................................................................................................... 17
2.1.2.1 Skeleton contesto kernel ......................................................................................... 17
2.1.3 Descrizione grafica .......................................................................................................... 18
2.2 Formula RTO ........................................................................................................................... 20
2.2.1 Contesto kernel ............................................................................................................... 20
2.2.1.1 Kernel built-in .......................................................................................................... 20
2.2.1.2 Modulo kernel ......................................................................................................... 23
2.2.2 Contesto utente ............................................................................................................... 24
2.3 Scelte implementative ............................................................................................................ 25
2.3.1 Interfaccia tra I due contesti ........................................................................................... 26
2.3.2 Accesso concorrenziale ................................................................................................... 27
2.3.3 Rilascio delle risorse ........................................................................................................ 28
3 Benchmark .................................................................................................................................... 32
3.1 Impatto modifiche apportate allo stack TCP .......................................................................... 33
2
3.2 Impatto sessione di registrazione ........................................................................................... 36
4 Casi di studio ................................................................................................................................. 39
4.1 Formula ‘chu’ .......................................................................................................................... 40
4.1.1 Connessioni outgoing ...................................................................................................... 42
4.1.2 Connessioni incoming ...................................................................................................... 49
4.1.3 Riassunto ed osservazioni ............................................................................................... 52
4.2 Formula ‘speedy’ .................................................................................................................... 53
4.2.1 Connessioni outgoing ...................................................................................................... 55
4.2.2 Riassunto ed osservazioni ............................................................................................... 61
Conclusioni ....................................................................................................................................... 63
Referenze ......................................................................................................................................... 65
Appendice ........................................................................................................................................ 66
3
INDICE DELLE FIGURE
Figura 2.1 Strutture di supporto alla registrazione RTT e RTO .................................................................................... 12
Figura 2.2 Associazione tra strutture di supporto alla registrazione e quella sock ..................................................... 13
Figura 2.3 Sessione di registrazione RTT e RTO. Buffer i – 2: già elaborato; i – 1: pieno, da elaborare; i + 2:
ancora da riempire ...................................................................................................................................................... 19
Figura 2.4 Associazione tra strutture di supporto all’aggiornamento dinamico di RTO e quella sock ........................ 21
Figura 2.5 Rilascio risorse relative ad una sessione di registrazione (1 di 2) ............................................................... 30
Figura 2.6 Rilascio risorse relative ad una sessione di registrazione (2 di 2) ............................................................... 31
Figura 3.1 Ambiente di test. Macchina A (Vbox): kernel NON modificato; macchina B (Vbox): kernel
modificato; macchina C: server in ascolto, in esecuzione sulla macchina ospite (Windows7) .................................... 34
Figura 3.2 Confronto in base alla “durata di upload” ................................................................................................. 35
Figura 3.3 Ambiente di test. Macchina A (Vbox): kernel modificato; macchina B (Vbox): kernel modificato
sessione di registrazione in atto; macchina C: server porta 80 in locale ..................................................................... 37
Figura 3.4 Confronto in base alla “durata di upload” ............................................................................................... 388
Figura 4.1 Ambiente di test ......................................................................................................................................... 42
Figura 4.2 Confronto in base alla “durata di upload” ................................................................................................. 43
Figura 4.3 Confronto in base alla “densità di probabilità” e “distribuzione cumulativa” ........................................... 43
Figura 4.4 Confronto in base alla “durata di upload” e “syn inviati” .......................................................................... 44
Figura 4.5 Confronto in base alla “densità di probabilità” e “distribuzione cumulativa” ........................................... 45
Figura 4.6 Ambiente di test ......................................................................................................................................... 46
Figura 4.7 Confronto in base alla “durata di upload” e “syn inviati” .......................................................................... 47
Figura 4.8 Confronto in base alla “densità di probabilità” e “distribuzione cumulativa” ........................................... 48
Figura 4.9 Confronto in base alla “durata di download” e “synack inviati” ................................................................ 50
Figura 4.10 Confronto in base alla “densità di probabilità” e “distribuzione cumulativa” ......................................... 51
Figura 4.11 Riassunto risultati ..................................................................................................................................... 52
Figura 4.12 Ambiente di test ....................................................................................................................................... 54
Figura 4.13 Confronto in base alla “durata di upload” e “rto scaduti” ....................................................................... 55
Figura 4.14 Confronto in base alla “densità di probabilità” e “distribuzione cumulativa” ......................................... 56
Figura 4.15 Confronto in base alla “durata di upload” e “rto scaduti” ....................................................................... 57
Figura 4.16 Confronto in base alla “densità di probabilità” e “distribuzione cumulativa” ......................................... 58
Figura 4.17 Confronto in base alla “durata di upload” e “rto scaduti” ....................................................................... 59
Figura 4.18 Confronto in base alla “densità di probabilità” e “distribuzione cumulativa” ......................................... 60
Figura 4.19 Riassunto risultati ..................................................................................................................................... 61
4
INTRODUZIONE
TCP è un protocollo affidabile, che garantisce la trasmissione dei dati tra due endpoint
costituenti la connessione. Tale obiettivo viene raggiunto attuando delle politiche di
ritrasmissione. L’endpoint trasmittente, in mancanza di conferma dell’avvenuta ricezione
dei dati dall’endpoint remoto entro un tempo prestabilito (a causa di ritardi di rete o di
perdita), deve ritrasmettere i dati non ancora confermati. Essi vengono inviati nuovamente
allo scadere di RTO (Retransmission Timeout), grandezza stimata del timeout di
ritrasmissione ed aggiornata dinamicamente anche in base a RTT (Round Trip Time),
grandezza misurata del tempo d'andata e ritorno.
Le formule per l’aggiornamento dinamico di RTO utilizzate nei sistemi operativi odierni
sono quelle che col tempo si sono dimostrate migliori nei contesti più generici. In alcuni
campi particolari, tuttavia, in funzione dell'utilizzo (data streaming, command protocol,
ecc) oppure del mezzo di comunicazione (intranet vs internet, wired vs wireless, ecc),
formule alternative possono portare a risultati migliori. Tale formula per poter essere
utilizzata in un contesto reale, deve però essere sottoposta ad un processo iterativo di
analisi e test, al fine di valutare la sua efficacia e/o efficienza.
In questa tesi è stata costruita un infrastruttura basata su kernel Linux che consente di:
• ottenere informazioni sui valori di RTT e RTO relativi ad una connessione
• modificare la formula per l’aggiornamento dinamico di RTO: essa può essere
associata ad una singola connessione oppure a tutto il sistema
Grazie all’infrastruttura oggetto di questa tesi, è possibile modificare la formula per il
calcolo di RTO e testarne immediatamente gli effetti introdotti nella comunicazione, senza
dover far ripartire il sistema operativo, o tanto meno ricompilare il kernel. Volendo
analizzare più in dettaglio suddetti effetti si può accedere ai valori RTT e RTO relativi ad
una connessione TCP.
Il primo capitolo, Architettura, offre una panoramica generale dell’infrastruttura proposta.
Ulteriori dettagli realizzativi seguono nel secondo capitolo, Implementazione. La
5
valuazione dell’impatto dovuto alle modifiche apportate, sulle performance del sistema è
l’argomento del terzo capitolo, Benchmark. Nel quarto capitolo, Casi di studio, vengono
analizzati due casi di studio utilizzando l’infrastruttura proposta.
6
1. ARCHITETTURA
Da un punto di vista architetturale l’infrastruttura proposta è composta da due sottosistemi.
Al primo spetta il compito di bufferizzare i valori RTT e RTO in strutture dati in memoria,
nel contesto kernel, quindi la loro esportazione in quello utente per ulteriori elaborazioni. Il
secondo sottosistema invece, riguarda la formula per l’aggiornamento dinamico di RTO:
come crearle e/o modificarle, aggiungerle nel sistema ed infine associarle alle connessioni
TCP. Nonostante lo scopo del primo sottosistema è quello di rendere disponibili utili
informazioni al secondo, ognuno dei due può esistere indipendentemente dall’altro.
1.1 Registrazione RTT e RTO
I valori di RTT e RTO vengono calcolati quindi aggiornati nel contesto kernel. Le
condizioni per le quali questo avviene sono le seguenti:
• avvenuta ricezione di un pacchetto o insieme di
nel qual caso RTT e RTO vengono aggiornate
• timeout d’avvenuta ricezione per un pacchetto o insieme di
nel qual caso RTO viene aggiornata
• connessione appena stabilita
nel qual caso RTO viene aggiornata
• errore ‘host unreachable’ pervenuto dal modulo icmp
nel qual caso RTO viene aggiornata
Ogni volta che una delle condizioni di sopra ha luogo, i valori vengono memorizzati nelle
apposite strutture dati in memoria. La memorizzazione riguarda sia RTT che RTO
indipendentemente dalla condizione verificata. Può essere pensata come un’istantanea di
RTT e RTO, il cui scatto avviene a fronte di una delle condizioni di cui sopra. Assieme ai
7
valori di RTT e RTO vengono memorizzati l'istante temporale e il tipo di condizione
verificatasi al fine poter distinguere successivamente nella fase di elaborazione.
Con l'utilizzo di un modulo kernel i valori bufferizzati vengono resi disponibili al contesto
utente. Pertanto vengono creati, durante la fase di boot, una serie di device il cui scopo è
proprio quello di accedere alle funzionalità del modulo kernel. Per accedere ai dati
d’interesse è stato implementato un ulteriore layer al fine di semplificare quanto più
possibile il processo da parte dell'operatore. L'unico compito spettante al programmatore è
appunto l'elaborazione stessa dei dati.
1.1.1 Utilizzo
Segue una breve descrizione, di una sequenza d’operazioni da eseguire per accedere ai
valori RTT e RTO relativi ad una connessione.
• apertura device
l'esecuzione di questa operazione richiede le seguenti informazioni passate a loro
volta tramite una struttura come parametro in ingresso:
o device
che verrà utilizzato come punto di ingresso al contesto kernel
• inizio sessione di registrazione
il concetto di sessione di registrazione è inteso come "registrazione dati in corso".
L'inizio della sessione richiede le seguenti informazioni passate a loro volta tramite
una struttura come parametro in ingresso:
o connessione tcp
identificata con la coppia [(ip:port)src, (ip:port)dst] ai quali valori di RTT e
RTO si dichiara l’interesse
o callback
8
“un puntatore di funzione” nel contesto utente, che viene chiamato dal
contesto kernel in presenza di dati nuovi da elaborare
Nel caso l’operazione avesse esito positivo la connessione scelta non sarà più
disponibile per un’altra sessione di registrazione se non alla fine di quella già in
corso
• fine sessione di registrazione
alla fine di questa operazione, la connessione scelta diventa disponibile per una
successiva sessione di registrazione
• chiusura driver
La 2° e 3° operazione, ovvero inizio e fine di una sessione di registrazione, possono essere
reiterate pur utilizzando lo stesso device aperto, mantenendo però l’ordine. In questo modo
è possibile attuare più di una sessione in sequenza. Da evidenziare il fatto che la sessione
attiva ha l’esclusività sul device: non è possibile attuare una ulteriore se non alla fine di
quella già in corso. Per scelta, è stato preferito la semplicità di utilizzo (apertura di un
ulteriore driver) alla complesità richiesta (demultiplexing, api più complesse).
1.2 Formula aggiornamento dinamico RTO
Il secondo sottosistema riguarda la formula per l’aggiornamento dinamico di RTO. Esso
consente di creare e/o modificare, aggiungere e/o rimuovere le formule dal sistema. Inoltre,
è possibile impostare una formula di default (utilizzata da tutte le connessioni create da
quel momento in poi) oppure a scelta, specificatamente ad una connessione.
La formula per il calcolo di RTO utilizzata dal kernel è proposta nella forma di una
funzione. Tale funzione è presente nel codice kernel, quindi apportare modifiche equivale
ad una ricompilazione dello stesso. Purtroppo questa operazione richiede un tempo di
esecuzione non indifferente.
9
Con lo strumento proposto in questa tesi, la formula per l’aggiornamento dinamico di RTO
viene caricata sotto forma di un modulo kernel. In questo modo essa si può modificare
senza dover ricompilare il kernel. Nel kernel vi sono state apportate delle modifiche al fine
di rendere disponibili tali moduli allo stack TCP. I moduli implementano le funzionalità
basi tra le quali la funzione che appunto aggiorna il valore RTO. Tale funzione viene
chiamata ogniqualvolta RTO viene aggiornata. La formula attualmente in uso nel kernel è
stata implementata come modulo, caricato automaticamente in fase di boot del sistema.
Utilizzando l'interfaccia ioctl-sockopt è possibile associare una formula a scelta tra quelle
disponibili nel sistema, ad una specifica connessione TCP. Infine utilizzando l'interfaccia
sysfs si può impostare una formula tra quelle disponibili come default.
1.2.1 Utilizzo
L'utilizzo della funzionalità offerta comprende da una parte la possibilità di modificare le
formule e dall'altra quella di associare esse ad una specifica connessione a scelta.
1.2.1.1 Gestione formula per calcolo RTO
La formula viene implementata nella forma di un modulo kernel. La creazione della
formula quindi, equivale all'implementazione del modulo kernel. L'aggiunta e la rimozione
invece equivalgono all’inserimento ed alla rimozione di essa dalla lista dei moduli
disponibili.
Tramite l’interfaccia sysfs del kernel è possibile impostare una delle formule disponibili
come default. Ogni connessione nuova, se non diversamente specificato, utilizzerà la
formula di default per il calcolo dinamico di RTO.
1.2.1.2 Associazione ‘formula 2 connessione’
L’associazione di una specifica formula per l’aggiornamento dinamico di RTO ad una
connessione è realizzabile tramite l’utilizzo di due diverse interfacce. La prima interfaccia
è quella tipica per la configurazione delle connessioni tcp (setsockopt). Chiamare la suddetta
10
syscall con il nome della formula scelta fa si che da quel istante in poi la, i valori di RTO
vengano calcolati con quella formula. E’ il caso di evidenziare che tale syscall implica che
la connessione TCP sulla quale si vuole intervenire è stata creata dal processo che sta
effettuando la chiamata stessa. Quest’ultimo è dovuto al fatto che il parametro passato in
ingresso alla setsockopt (file descriptor con la quale si identifica la connessione TCP), non è
dato a sapere se non nel contesto del processo dove la connessione stessa è stata creata.
Come seconda interfaccia, si può utilizzare quella per la sessione di registrazione dei valori
di RTT e RTO. Una volta aperto il device ed iniziata la sessione di registrazione, si può
utilizzare la funzionalità del device per l’impostazione di una formula specificatamente ad
una connessione TCP. In questo modo si ha la possibilità di intervenire anche su una
connessione creata da un altro processo.
11
2. IMPLEMENTAZIONE
In questo capitolo viene fatta una descrizione più dettagliata dell’infrastruttura proposta.
Riallaciandosi all’aspetto funzionale, verrà puntata la lente d’ingrandimento su ognuno dei
due sottosistemi. La loro descrizione riguarderà l’implementazione sia nel contesto kernel
che quello utente. Per poi proseguire con una discussione su varie scelte implementative
fatte.
2.1 Registrazione RTT e RTO
La registrazione dei valori di RTT e RTO avviene sia nel contesto kernel che quello
utente. Nel contesto kernel, l’implementazione segue delle linee guida con un occhio di
riguardo alla prestazione ed alla stabilità. Un possibile errore in questo contesto
renderebbe il tutto instabile ed addirittura inutilizzabile. Nel contesto utente invece,
l’obiettivo è stato quello di fornire api ben progettate e semplici da utilizzare.
2.1.1 Contesto kernel
L’implementazione nel contesto kernel riguarda una componente “statica”, di supporto per
l’intera infrastruttura. In questa categoria fanno parte tutte le modifiche apportate nella
struttura del kernel che richiedono la sua ricompilazione. Le modifiche apportate alla
struttura sock, i punti individuati nel kernel ove le condizioni si verificano ne fanno parte.
La seconda categoria riguarda la parte “dinamica”, le cui modifiche non necessitano la
ricompilazione. Il modulo che si interfaccia con il contesto utente per l’esportazione dei
dati ne fa parte.
12
2.1.1.1 Kernel built2in
Il termine built-in rende meglio l’idea sull’argomento di questo paragrafo. Infatti riguarda
tutte le modifiche integrate nel kernel stesso. Le modifiche fanno da ponte tra il kernel e la
nuova infrastruttura.
• strutture nuove aggiunte
La struttura zsample_buffer è il buffer dove i valori RTT e RTO vengono
bufferizzati. Essa ospita inoltre, delle variabili con le quali tra i due contesti viene
attuato del protocollo di comunicazione. La struttura zsample_buffer_holder è un
insieme di zsample_buffer. La suddivisione della memoria disponibile in tanti
buffer diminuisce la possibilità di problemi dovuti all’accesso concorrenziale.
Figura 2.1 Strutture di supporto alla registrazione RTT e RTO
La struttura zsample_sniff_session contiene tutto il necessario per una sessione di
registrazione. Essa contiene un riferimento all’array di buffer ove i valori RTT e
RTO vongono memorizzati. L’accesso al modulo è reso possibile con un
13
‘puntatore di funzione‘ (take_sample). Infine, con la presenza di variabili flag, il
rilascio della memoria relativa alla sessione viene fatto in tutta sicurezza.
• associazione tra la connessione TCP e le strutture nuove
la struttura di supporto, zsample_sniff_session, viene associata a quella sock
indirettamente tramite una ulteriore, la zsample_sock_sniff_session_wrapper. In
questo modo si disaccoppia il corso d’azione tra lo stack TCP ed il modulo kernel.
Il processo che si occupa del rilascio delle risorse utilizza appunto questa struttura
per riconoscere se una connessione è chiusa, quindi rilasciare la relativa memoria
occupata da sessioni di registrazione.
Figura 2.2 Associazione tra strutture di supporto alla registrazione e quella sock
Le modifiche apportate alla struttura sock riguardano sia la registrazione che
l’utilizzo della formula per l’aggiornamento dinamico di RTO. I campi che
riguardano la registrazione sono necessari per la bufferizzazione e per il rilascio
14
delle relative risorse. Invece i campi che riguardano l’aggiornamento dinamico
forniscono delle informazioni utili concernenti la connessione durante la fase
3WHS.
• inserite nel codice kernel le chiamate per la bufferizzazione dei dati
nel codice del kernel, nei punti dove le condizioni di aggiornamento di RTT e/o
RTO hanno luogo, sono state apportate delle funzioni. Tramite esse il corso
d’esecuzione viene instradato verso l’infrastruttura proposta. Ogni chiamata ha
come parametri la struttura sock appartenente ed il tipo di condizione verificata.
• sessioni di registrazione
onde permettere la registrazione dei valori RTT e RTO sono state implementate
delle api visibili solo nel contesto kernel (tipicamente i moduli).
o int take_sample(struct sock *sk, int origin, void *data)
la funzione con la quale il corso d’azione dello stack viene instradato nel
modulo kernel. L’implementazione di questa api consiste in una serie
opportuni controlli affinche i riferimenti alle varie strutture siano validi.
Successivamente viene fatta la chiamata al ‘puntatore di funzione’ (vedasi
zsample_sniff_session) definita nel modulo kernel. Tale funzione viene
chiamata ogni volta che una delle condizioni d’aggiornamento di RTT e
RTO ha luogo.
o struct zsample_sniff_session* connectionSearch(unsigned int saddr, unsigned int daddr, unsigned short sport, unsigned short dport, int *ret)
è la funzione che si occupa di individuare tra le connessioni attualmente
stabilite, quella identificata dai parametri in ingresso. Tale funzione viene
chiamata dal modulo kernel quando l’utente indica interesse nel registrare i
valori RTT e RTO di una connessione TCP. Nel caso la connessione
venisse individuate, la struttura zsample_sniff_session viene creata, quindi
ritornata come parametro di return. Qualora la connessione non venisse
15
individuata oppure non fosse disponibile in quanto già utilizzata in un’altra
sessione il parametro ritornato è NULL.
o int connectionRelease(struct zsample_sniff_session *rttKernel)
tale funzione termina la sessione di registrazione. Successivamente la
connessione diventa disponibili a future sessioni e le relative risorse
vengono liberate. Le condizioni per cui una sessione di registrazione viene
terminata sono per scelta dell’applicativo nel contesto utente oppure perchè
la connessione TCP viene chiusa.
• processo di rilascio delle risorse
è il processo che si occupa del rilascio delle risorse dopo che una sessione di
registrazione viene terminata. Esso viene fatto partire già durante il boot del
sistema. Il suo compito è quello di mantenere traccia in una lista globale, di tutte le
strutture create come supporto alle sessioni di registrazione. Ad ogni sessione
nuova corrisponde un inserimento della relativa struttura nella lista globale (vedasi
connectionSearch). Rispettivamente ad ogni sessione terminata la relativa struttura
viene segnata come ‘da rimuovere’ (vedasi connectionRelease). Il rilascio della
memoria viene fatto in modalità deferred, ovvero posticipata per eliminare
l’overhead dovuto alla protezione dell’accesso concorrenziale tra lo stack tcp ed il
modulo kernel.
2.1.1.2 Modulo kernel
Le funzionalità integrate nel kernel vengono esposte al contesto utente con l’utilizzo dei
moduli kernel. Il loro compito è quello di interfacciarsi da una parte con lo stack TCP e
dall’altra con il contesto utente. Con il contesto utente tale interfacciamento è reso
possibile tramite un device a caratteri: infatti durante la fase di boot del sistema vengono
creati una serie di device, come specificato in /etc/rc.d/rc.modules. Invece dallo stack TCP il
modulo è raggiungibile tramite le api introdotte nella sezione precedente (vedasi
take_sample). Tale modulo viene caricato già nella fase di boot del sistema, come specificato
16
in /etc/rc.d/rc.modules.
Interfaccia con il contesto kernel
Il modulo implementa la funzione take_sample (distinta da quella dello stesso nome
integrata nel kernel) che svolge effettivamente l’operazione di bufferizzazione dei valori
RTT e RTO. L’implementazione volutamente viene fatta nel modulo affinche sia
facilmente modificabile. E’ compito suo bufferizzare i dati opportunamente e soprattutto
notificare il contesto utente in caso si verifichi una condizione particolare (es. buffer
riempito ecc). Quando una sessione di registrazione inizia, uno dei parametri della relativa
struttura è appunto un puntatore di funzione a questa chiamata.
Interfaccia con il contesto utente
L’accesso al modulo, quindi al contesto kernel viene fatto utilizzando un device a caratteri.
Perciò per poter utilizzare le funzionalità offerte, in primis il device va aperto. Seguendo le
linee guida dell’interfaccia ioctl tipica dei device, sono state implementate tutte le
funzionalità richieste. Per quanto riguarda l’esportazione dei dati tra i due contesti esso
viene fatto tramite il memory mapping, ovvero una zona di memoria condivisa tra i due
contesti. In questo modo si risparmia una copia dei dati tra i due contesti. Segue una breve
descrizione delle api ioctl disponibili, in base al parametro ioctl_cmd:
• SESSION_ON_IOCTL
viene fatta la ricerca, tra quelle disponibili, sulla connessione TCP come dai parametri
in ingresso identificata. In caso tale ricerca avesse esito positivo, una struttura
(zsample_sniff_session) viene creata, pronta per l’uso. Alla struttura appena inizializzata,
viene passato sotto forma di un ‘puntatore di funzione’ il riferimento alla funzione
take_sample, ed anche l’oggetto wait_queue_head_t col quale viene segnalato il contesto
utente della ‘presenza di dati da elaborare’.
• WAIT_DATA_IOCTL
la chiamata blocca fino al massimo di 1 sec, in attesa di una segnalazione di ‘presenza
di dati da elaborare’ dal modulo kernel. Se entro tale tempo la segnalazione non
perviene, essa ritorna al chiamante ed è compito di quest’ultimo ritentare la chiamata.
17
Nel caso la connessione TCP, oggetto della sessione di registrazione, venisse chiusa,
questo evento è segnalato al contesto utente.
• GET_RTO_FORMULA_IOCTL / SET_RTO_FORMULA_IOCTL
queste ioctl sono utili nel caso si volesse intervenire sulla formula per l’aggiornamento
dinamico di RTO, relative ad una connessione TCP creata da un altro processo.
• SESSION_OFF_IOCTL
la sessione va in ogni caso terminata, sia per iniziativa dell’applicativo nel contesto
utente oppure perchè la connessione viene chiusa. Essa svolge i seguenti compiti:
o rilascia la struttura dati relativa alla sessione di registrazione
o la connessione TCP viene segnata come libera, quindi candidata ad eventuali
future sessioni di registrazione
2.1.2 Contesto utente
Il contesto utente si interfaccia col modulo kernel tramite un device a caratteri.
Interfacciarsi col modulo implica l’esecuzione delle seguenti operazioni:
• apertura del device
• memory mapping
• estrazione dei dati dal contesto kernel
• chiusura del device
Onde rendere più semplice il compito al programmatore è stato implementato uno skeleton,
nella forma di un layer superiore. Si occupa di eseguire le operazioni di cui sopra,
nascondendo i dettagli e proponendo un’interfaccia più semplice.
2.1.2.1 Skeleton contesto utente
La struttura rtt_ctrl, creata come supporto all’infrastruttura, raggruppa tutto il necessario.
Riempita opportunatamente (device da utilizzare, puntatore di funzione da richiamare ecc)
essa verrà utilizzata successivamente come parametro di tutte le api. Uno dei parametri di
18
tale struttura è il ‘puntatore di funzione’ che verrà chiamato in presenza di dati da
elaborare. Infatti, il thread creato dallo skeleton, che si occupa di estrarre i dati dal modulo
kernel, chiamerà tale puntatore di funzione per rendere disponibili al programmatore i dati.
Ovviamente l’implementazione di questa funzione spetta al programmatore stesso. Tipici
utilizzi sono: salvataggio in file, plot del grafico in tempo reale e via dicendo.
Le api begin_session e end_session possono essere chiamate in successione, pur mantenendo
aperto anche lo stesso device. In tutte le api il parametro err_code è di tipo ‘in uscita’ e ha
un significato particolare in funzione dell’api stessa.
• int open_device(rtt_ctrl* ctrl, int *err_code);
• int close_device(rtt_ctrl* ctrl, int *err_code);
• int begin_session(rtt_ctrl* ctrl, int *err_code);
• int end_session(rtt_ctrl* ctrl, int *err_code);
Le seguenti api vengono riportate per completezza, nonostante riguardano la parte che si
occupa della formula per l’aggiornamento dinamico di RTO. Le funzionalità offerte sono
facilmente intuibili dalle denomizazioni stesse.
• int get_available_rto_formula(char *holder, int max_len);
• int get_current_sniffing_connection_rto_formula(char *holder, int max_len);
• int set_current_sniffing_connection_rto_formula(char *holder);
2.1.3 Descrizione grafica
Il processo che si occupa della registrazione dei valori RTT e RTO viene eseguito sia nel
contesto kernel che quello utente. La generazione degli eventi, il passaggio tra i due
contesti rendono il tutto non facilmente intuibile. Con la seguente descrizione grafica ed i
seguenti commenti sui vari passaggi si cerca appunto di rendere più apprensibile tale
processo.
19
Figura 2.3 Sessione di registrazione RTT e RTO. Buffer i – 2: già elaborato; i – 1: pieno, da elaborare; i + 2: ancora da
riempire
1 L’applicativo nel contesto utente dopo aver aperto il device, selezionato la connessione TCP d’interesse, effettua una chiamata ioctl bloccante-sincrona con timeout 2 La chiamata ioctl di cui sopra, ritorna al thread chiamante in presenza di dati da elaborare oppure per timeout. In ambedue i casi l’applicativo ritenta di nuovo la chiamata ioctl (fin tanto che non viene predisposto altrimenti es. CTRL-C od altro) 3 Nel frattempo eventuali condizioni verificate nello stack TCP (ack ricevuti, timeout scaduti) generano i valori RTT e RTO che vengono bufferizzati 4 Una volta che uno dei buffer viene riempito lo stesso stack TCP segnala il thread chiamante della presenza di dati da elaborare 5 A questo punto il thread chiamante a cavallo tra i contesti utente e kernel rientra da quest’ultimo in quello utente 6 Una volta ritornato al thread chiamante, riconoscendo la presenza nel buffer circolare di dati da elaborare, il thread si presta all’elaborazione dei dati come dalla logica richiesta (salvataggio in un file, esecuzione di statistiche storiche, visualizzazione del grafico in tempo reale ecc). Da notare come in questa fase la prossima chiamata ioctl viene effettuata solo dopo che tutti i dati (anche quelli che eventualmente arrivano nel frattempo) sono stati elaborati, onde eliminare quanto più possibile i cross-boundaries (le chiamate ioctl).
20
2.2 Formula RTO
La formula per l’aggiornamento dinamico di RTO è implementata nella forma di un
modulo kernel. La sua implementazione segue le regole generali di un modulo kernel
(entry e exit point, ecc), ed inoltre implementa le api necessarie all’infrastruttura proposta.
2.2.1 Contesto kernel
Nel contesto kernel l’implementazione riguarda una componente “statica” che consente
l’interfacciarsi tra lo stack TCP ed i moduli kernel tramite i quali le formule stesse sono
implementate. Esso concerne tutte le modifiche apportate nella struttura del kernel che
richiedono la ricompilazione dello stesso. Le modifiche apportate alla struttura sock, i punti
individuati nel kernel dove la formula viene selezionata per la prima volta, dove viene
scelta una diversa formula rispetto a quella di default, dove le chiamate al modulo vengono
fatte ne fanno parte. L’altro componente riguarda la parte “dinamica” le cui modifiche non
necessitano la ricompilazione del kernel. Esso concerne i moduli kernel per le formule.
2.2.1.1 Kernel built2in
Il termine built-in rende meglio l’idea sull’argomento di questo paragrafo. Infatti riguarda
tutte le modifiche integrate nel kernel stesso.
• strutture nuove aggiunte
la struttura nuova aggiunta tcp_rto_formula_ops, oltre ai vari campi tipici dei
moduli kernel (es. owner) è composta da una serie di ‘puntatori di funzione’.
21
Figura 2.4 Associazione tra strutture di supporto all’aggiornamento dinamico di RTO e quella sock
Alla creazione di una struttura sock segue anche un’opportuna inizializzazione del
modulo che calcolerà i valori di RTO. E’ appunto tramite questi puntatori, che lo
stack TCP raggiunge il modulo kernel.
• chiamate inserite nel codice dello stack TCP
in vari punti dello stack TCP sono state aggiunte le chiamate verso i moduli kernel.
In primis, alla creazione di una struttura sock è stata aggiunta della logica che
opportunamente associa la connessione tcp al modulo (*init). In questa fase
d’inizializzazione viene intanto aumentata la variabile ref_cnt del modulo kernel il
cui compito è quello di impedire che il modulo possa essere rimosso dal sistema
22
mentre in uso. Poi vengono inizializzate una serie di costanti relativa alla formula
RTO. Infine la struttura nuova rappresentante il modulo viene aggiunta come
referenza a quella sock rendendosi cosi disponibile all’utilizzo. Nel kernel, ove
RTO viene aggiornata, il corso d’azione viene instradato tramite i puntatori di
funzione, al modulo kernel rappresentato dalla struttura referenziata. Le condizioni
per le quali questo si verifica sono le seguenti:
o ack di un pacchetto o insieme di
o RTO scaduto
o connessione appena stabilita
o evento di ‘host unreachable’ pervenuto dal modulo icmp
• modulo integrato nel kernel
avendo modificato opportunamente in vari punti lo stack TCP, si vuole altrettanto
fare il modo che il sistema sia comunque in una situazione ben definita. Infatti nel
kernel è stato aggiunto un modulo che implementa una formula di default, caricata
durante il boot del sistema. Essa implementa in dettaglio quanto già presente nel
kernel prima delle modifiche. Quindi tranne per il fatto che il corso d’azione viene
instradato nel modulo, l’implementazione di default non ha alcuna differenza
rispetto a quella precedentemente implementata dal kernel prima delle modifiche.
• chiamate per la gestione delle formule
una volta che una formula rto viene inserita nel kernel essa necessita qualche forma
di gestione. Per questo nel kernel sono state apportate delle modifiche onde
consentire:
o impostare una formula come globale o di default
o impostare una formula per una specifica connessione TCP
Nel primo caso viene utilizzata l’interfaccia sysctl del kernel. Invece l’associazione
di una formula ad una connessione TCP è resa possibile tramite l’interfaccia ioctl
stessa dei socket.
23
2.2.1.2 Modulo kernel
I moduli kernel che aggiornano RTO devono implementare delle api con signature ben
definite. Per iniziare, api module_init ed module_exit le quali vengono chiamate
rispettivamente al caricamento ed alla rimozione del modulo stesso. Le seguenti api invece
riguardano l’implementazione della logica per l’aggiornamento dinamico di RTO:
• init
• release
• tcp_calc_synack_rto
• tcp_set_rto
• tcp_set_rtt
La funzione init è chiamata la prima volta che una connessione vuole utilizzare il modulo
in questione. Il modulo incrementa il valore ref_cnt affinche esso non possa essere
rimosso dal sistema mentre in uso. Nel nostro caso nella funzione init vengono inizializzate
variabili della struttura sock con le quali si controllano i valori massimi, minimi ed iniziali
di RTO, attualmente costanti nel kernel. Altre possibili operazioni possono essere
inizializzazioni di eventuale memoria da utilizzare, possibili riferimenti aggiornati ecc.
La funzione release è speculare alla init. Essa è chiamata quando la connessione TCP non
utilizzerà più il modulo in questione. Va evidenziato, che questa chiamata decrementa
anche la variabile ref_cnt del modulo, rendendolo cosi un possibile candidato alla
rimozione. Per questo motivo si deve essere assolutamente sicuri che il modulo non verrà
in alcun modo più utilizzato. Rispettivamente, possibili operazioni sono il rilascio di
eventuale memoria occupata, riferimenti aggiornati ecc.
Una connessione TCP appena creata e prima di essere stabilita si trova in uno dei seguenti
stati in base al tipo:
• connessione outgoing ovvero in uscita (connect)
stato TCP_SYN_SENT, intesa come ‘inviato un pacchetto SYN, quindi in attesa del
relativo ACK’
24
• connessione incoming ovvero in ingresso (accept)
stato TCP_SYN_RECV, intesa come ‘inviato ACK ad un pacchetto SYN pervenuto,
quindi in attesa del relativo ACK’
A differenza delle altre, le connessioni incoming da un punto di vista delle strutture dati di
supporto, necessitano di una diversa implementazione. Infatti il kernel durante lo stato
TCP_SYN_RECV implementa la logica opportuna con una struttura (request_sock) dati di
supporto più “leggera” dal punto di vista della memoria. Quindi il modulo kernel esporta
due funzioni per il calcolo dinamico di RTO: una per le connessioni (sia incoming che
outgoing) una volta stabilite ed un’altra per le connessioni incoming nella fase
TCP_SYN_RECV ovvero prima che esse siano stabilite.
La funzione tcp_calc_synack_rto viene utilizzata per aggiornare il valore di RTO per una
connessione incoming non ancora stabilita. La connessione TCP entra in questo stato
appena risponde col proprio ACK ad un pacchetto SYN in ingresso. Rimane in questo stato
finche non riceve l’ACK relativo dall’altra estremità, dopo il quale la connessione si sposta
nello stato TCP_ESTABLISHED.
La funzione tcp_set_rto viene utilizzata per aggiornare il valore di RTO per una
connessione TCP in tutti gli altri casi tranne quello precedente.
La funzione tcp_set_rtt viene utilizzata per aggiornare il valore di RTT nella struttura
tcp_sock. Tale funzione è chiamata dallo stack quando un pacchetto o insieme di viene
confermato. In questo modo si ha la possibilità di accedere ai valori RTT nel contesto del
modulo kernel.
2.2.2 Contesto utente
L’interazione tra il contesto utente ed i moduli è riassunta nel loro caricamento e
rimozione. In Linux con l’utilizzo di comandi shell è possibile eseguire tali operazioni:
• caricamento - loading
25
root# insmod nome_formula.ko
• rimozione - unloading
root# rmmod nome_formula
Una volta caricati nel sistema, i moduli sono posti in una lista globale. Tra le formule
disponibili una sarà quella di default, ovvero la formula che ogni connessione TCP
utilizzerà se non diversamente specificato. Tramite l’interfaccia sysfs è possibile avere
informazioni sulle formule disponibili nel sistema, leggere ed impostare quella di default:
• tcp_rto_formula, r/w per leggere/impostare la formula rto di default
cat /proc/sys/net/ipv4/tcp_rto_formula echo ‘aaa’ > /proc/sys/net/ipv4/tcp_rto_formula
• tcp_available_rto_formula, r per reperire la lista delle formule disponibili
cat /proc/sys/net/ipv4/tcp_available_rto_formula
Per impostare una particolare formula ad una specifica connessione vengono utilizzate le
syscall setsockopt/getsockopt. Esse sono delle chiamate simili alle ioctl, ma specifiche alle
socket.
• consente la lettura della formula associata alla connessione tcp (sockfd)
getsockopt(sockfd, IPPROTO_TCP, TCP_RTO_FORMULA, (void*)&rto[0], (socklen_t*)
&RTO_FORMULA_LEN)
• consente l’associazione della formula “speedy” alla connessione tcp (sockfd)
setsockopt(sockfd, IPPROTO_TCP, TCP_RTO_FORMULA, (void*)&”speedy”,
strlen(&”speedy”))
2.3 Scelte implementative
La registrazione dei valori RTT e RTO è un processo che merita qualche approfondimento
in più. Esso opera a cavallo tra i due contesti ed inoltre ha un proprio impatto sulle risorse
di memoria e cpu. Quindi vanno indirizzate le seguenti problematiche:
26
• interfaccia per l’esportazione dei dati dal contesto kernel a quello utente
• accesso concorrenziale ai dati tra il produttore (stack TCP) ed il consumatore (skeleton)
• rilascio delle risorse utilizzate da sessioni di registrazione
2.3.1 Interfaccia tra i due contesti
I valori RTT e RTO memorizzati nel contesto kernel, affinche siano elaborati vanno
esportati in quello utente. Nel contesto utente si ha accesso ad un insieme di librerie più
ampio e ricco (basti pensare al floating point). Inoltre anche dal punto di vista della
conoscenza di programmazione, il contesto utente raggiunge una audience più ampia. Tale
processo non è una operazione semplice come ad esempio una copia dei dati da una zona
di memoria all’altra.
In un SO Linux, possibili interfacce tra il contesto kernel e quello utente sono le seguenti
(lista di certo non esaustiva):
• file
procfs, sysfs, configfs tipicamente utilizzate per la configurazione di parametri a livello kernel
• socket
tcp, udp e netlink tipicamente utilizzate per il passaggio di grandi quantità di dati. Da un punto di
vista della programmazione sono alquanto complessi, in compenso però godono delle proprietà
tipiche dei socket (caso tcp: l’affidabilità, caso udp: l’utilizzo dei datagram)
• ioctl
tipicamente tramite l’utilizzo di un device (a caratteri, blocchi ecc)
• mmap
memory mapping tipicamente utilizzati nei driver delle schede video per le alte prestazioni
offerte. In compenso però richiedono degli sforzi in più dal punto di vista della programmazione
Per adempiere ai compiti richiesti, fondamentalmente serve:
• un meccanismo che possa informare il contesto utente in caso di presenza di dati
• un meccanismo che consenta di esportare i dati dal contesto kernel a quello utente
27
La soluzione meglio adatta all’infrastruttura proposta è la seguente:
• utilizzo di un device a caratteri
che fornisce l’interfaccia ioctl tramite la quale si possono ottenere informazioni dal contesto kernel
• utilizzo del mmap (memory mapping)
per l’esportazione dei dati nel contesto utente
La scelta di sopra è dettata nel primo caso dalla semplicità ovvero minimo sforzo possibile
per ottenere le funzionalità richieste: tra i vari possibili device, il più semplice è quello a
caratteri. Nel secondo caso invece la motivazione è la prestazione. Infatti con una diversa
interfaccia (es. copy_to_user, socket etc) si andrebbe incontro ad una copia in più per il
passaggio dei dati tra i due contesti. Il memory mapping invece, espone la zona di memoria
del kernel (tramite opportune api) al contesto utente come se fosse nel medesimo,
eliminando quindi la necessità di una copia tra i due contesti.
2.3.2 Accesso concorrenziale
Per il passaggio dei dati tra i due contesti (kernel ed utente) viene utilizzata una zona di
memoria condivisa nella forma di un buffer. Essendo esso condiviso tra il produttore (che
aggiunge dati) ed il consumatore (che preleva dati) il problema dell’accesso concorrenziale
va indirizzato. Nel caso in questione si tratta di un unico produttore ed un unico
consumatore il che semplifica di molto la situazione. Questo vorrebbe dire che il momento
in cui la contesa avrà luogo sarà solamente quando ambedue vi accedono al buffer. Nel
caso vi fossero più consumatori e/o produttori oltre alla contesa appena accennata vi
sarebbe anche un’altra che dovrebbe serializzare i multipli produttori e/o consumatori che
siano. L’accesso serializzato al buffer è necessario in quanto nell’aggiornare gli indici
dell’array sia il consumatore che il produttore devono essere sicuri di non interferire col
lavoro dell’altro. Infatti, la prassi in questi casi chiede che l’accesso vada protetto con dei
lock, ovvero il locking a livello kernel col minore overhead.
Il produttore, nel nostro caso lo stack TCP, non si può permettere di aspettare che il
consumatore finisca il suo lavoro. Questo introdurrebbe ritardi, anche minimi che siano, al
28
corso d’azione dello stack TCP. Tali ritardi non solo graverebbero sulla performance del
sistema stesso, sull’andamento della connessione TCP, ma ‘sporcherebbero’ anche i valori
RTT e RTO stessi per i quali l’infrastruttura è stata costruita. Ne consegue che il corso
d’azione del produttore (lo stack TCP) non deve essere interrotto in alcun modo,
indipendentemente dalla velocità con la quale il consumatore possa elaborare i dati.
Una possibile soluzione al problema appena posto viene dall’utilizzo del buffer circolare.
In questo caso il produttore una volta raggiunto la fine del buffer, riparte dall’inizio. Ne
segue come corollario che se la velocità con la quale il produttore inserisce in coda i dati è
maggiore di quella con la quale il consumatore li rimuove, i dati più vecchi verrebbero
sovrascritti con i più nuovi. Ovviamente in tale situazione il produttore sposterebbe anche
l’indice del prossimo dato che il consumatore andrà a consumare e segnalare tale evento
tramite un flag. Sarà compito del consumatore riconoscere dal flag questa situazione e
comportarsi di conseguenza.
Con questa impostazione la contesa tra i due concorrenti non si verifica più: i corsi
d’azione di nessuno dei due viene interrotto in alcun modo dall’altro. Per quanto riguarda il
caso peggiore, ovvero la velocità del produttore maggiore di quella del consumatore,
l’impostazione proposta è sempre preferibile all’interruzione di uno dei due, in attesa della
fine del lavoro dell’altro. Purtroppo non esiste una soluzione al caso peggiore: non esiste
un buffer infinito! Va detto però, che nel nostro caso, la velocità del produttore
difficilmente sarà maggiore di quella del consumatore anche se il sistema stesso fosse sotto
stress: gli eventi oggetti di studio non vengono generati con tale frequenza.
2.3.3 Rilascio delle risorse
La zona di memoria condivisa tra il contesto kernel e quello utente è pursempre una risorsa
di sistema: va comunque liberata dopo il suo utilizzo. Tale zona di memoria è condivisa tra
due processi implicando che il rilascio da parte di uno potrebbe compromettere il corso
d’azione dell’altro. Nel nostro caso uno dei due processi viene ospitato nel contesto kernel
il che peggiora la situazione ulteriormente: un accesso di tipo reference ad una struttura
NULL porterebbe ad un crash del SO intero.
29
Proteggere l’accesso con un lock ha degli svantaggi. Lasciando stare per un attimo il
ritardo introdotto al processo in attesa di rilascio del lock, preoccupa molto di più il blocco
indefinito. Si pensi ad esempio ad un ‘process kill’ a livello utente che già mantiene il lock
sulla struttura. Bloccherebbe indefinitivamente il processo nel contesto kernel in attesa del
rilascio del lock. Anche nel caso in cui la chiusura della connessione TCP possa avere esito
positivo, le risorse (associate appunto alla connessione) non rilasciate, peserebbero a lungo
andare sulla stabilità del SO stesso.
La scelta fatta per l’infrastruttura proposta è quella del rilascio deferred ovvero posticipato.
Le risorse vengono rilasciate solamente quando ambedue i processi dichiarano che non ne
faranno più utilizzo. Ovviamente questo comporta della logica in più, ma consente anche
di eseguire l’operazione in tutta sicurezza. Per adempiere a questo compito l’infrastruttura
è stata dotata di una lista globale dove porre le strutture da rilasciare ed un processo che si
occuperà del loro rilascio. Sia la lista che il processo sono ospitati nel contesto kernel.
Ogni struttura inizializzata viene per prima associata a quella sock, ed in più aggiunta come
riferimento in tale lista. In questo modo si ha accesso alla struttura anche quando sia la
connessione che il processo nel contesto utente siano terminati. A quel punto, ovvero
quando la struttura viene segnalata da ambedue i processi come ‘da rilasciare’, il processo
percorrendo la lista e riconoscendola la rimuove, quindi ne rilascia le sue risorse
ritornandole al SO.
Sulla stessa connessione TCP, durante la sua vita, possono avere luogo diverse sessioni di
registrazione. Ognuna di queste sessioni avrà la propria struttura dati. Queste strutture dati
però, andranno rilasciate solamente quando la connessione tcp viene terminata ovvero
quando la struttura sock verrà rilasciata dallo stack tcp stesso. Fintanto che la connessione
TCP è ancora attiva non si può avere la certezza (alla luce anche di possibili future
modifiche del kernel) che nessun accesso verrà fatto dopo che le strutture della sessione
verranno rilasciate.
La lista di cui si accennava poco fa, in realtà è un insieme di due tali. Una legata allo stack
TCP, sock_wrapper_list e l’altra legata alle sessioni di registrazione, session_list. Segue un
esempio ed una descrizione grafica onde descrivere meglio il meccanismo.
30
Con stack = 0 viene indicata una connessione TCP ancora attiva, che alla chiusura diventa
stack = 1. Lo stesso ragionamento vale anche per la variabile module riferita però al
modulo kernel. Sia aa1 una struttura sock al quale corrispondono le sessioni aa1: 1 e aa1:
2. La modifica apportata dallo stack TCP a fronte della chiusura della connessione, alla
struttura in sock_wrapper_list viene propagata alle rispettive in session_list dal processo
che si occupa del rilascio delle risorse.
Figura 2.5 Rilascio risorse relative ad una sessione di registrazione (1 di 2)
La propagazione dell’evento “connessione tcp chiusa” viene fatta in due fasi (ecco quindi la
necessità di due liste) proprio per disaccoppiare i corsi d’azione. La prima fase consiste
31
nella segnalazione da parte dello stack TCP di questo evento ponendo la variabile stack del
relativo elemento nella lista sock_wrapper_list a 1. In questo modo lo stack TCP non è
obbligato a dover percorrere la session_list in cerca delle rispettive strutture riferite alle
sessioni. Infatti questo compito viene svolto dal processo di rilascio delle risorse.
Solamente quando anche i moduli segnaleranno di aver preso visione, quindi che non
utilizzeranno più le strutture condivise allora inizia la seconda fase. Anche in questo caso è
il processo di rilascio delle risorse che percorre la session_list liberando quindi le strutture
non più utilizzate.
Figura 2. 6 Rilascio risorse relative ad una sessione di registrazione (2 di 2)
32
3. BENCHMARK
Le modifiche apportate nel kernel implicano indubbiamente un impatto sulla performance
del sistema. Alla struttura sock sono state aggiunte dei riferimenti a quella di supporto
all’infrastruttura proposta. La struttura riferita riguarda sia l’aspetto ‘registrazione di RTT
e RTO’ che ‘formula per l’aggiornamento dinamico di RTO’. Anche il processo che in
background si occupa di rilasciare le risorse non più utilizzate, ha la propria componente di
impatto sulla performance.
Quanto accennato riguarda il sistema nel suo intero indipendentemente dal fatto se una
registrazione è attiva o meno. Qualora lo fosse, alle variabili che influiscono sulla
performance vanno aggiunte delle ulteriori. La struttura dati inizializzata per il passaggio
dei dati tra il livello kernel ed utente. Inoltre il thread a livello utente che si occupa appunto
di esportare i dati dal contesto kernel, implica ulteriori risorse utlizzate sia di memoria che
cpu.
Ai fini di un’analisi più semplificata, suddivideremo il problema in due. Il primo
riguarderà solamente le modifiche apportate al kernel, lasciando fuori dall’equazione la
sessione di registrazione. Verranno messi a confronto un kernel modificato ed uno non. Il
secondo riguarderà solamente la sessione di registrazione. Verranno messi a confronto due
kernel modificati, su uno dei quali però una sessione di registrazione è attiva.
Modifiche apportate allo stack TCP
Le seguenti operazioni verranno effettuate ogniqualvolta una delle condizioni di
aggiornamento di RTO ha luogo:
• accesso al modulo per aggiornare il valore di RTO
• controllo se una sessione di registrazione è attiva
Nel caso la seconda operazione avesse esito positivo, altre, riguardanti la parte che si
occupa della registrazione dei valori RTT e RTO, ne seguirebbero. Esse non vengono prese
in considerazione ai fini dell’analisi in quanto hanno un impatto attribuibile allo stack TCP
33
solamente quando una sessione di registrazione è in atto. Ambedue le operazioni hanno un
numero ben definito di istruzioni, non soggetto di alcun ritardo dovuto ad altri processi
quindi deterministiche.
Sessione di registrazione attiva
Nel caso di una sessione di registrazione saranno prese in considerazione le seguenti
operazioni:
• memorizzazione dei valori RTT e RTO nelle opportune strutture dati
• esportazione dei dati tra il contesto kernel e quello utente
In questo caso abbiamo trascurato di proposito l’operazione effettuata dall’applicativo sui
dati esportati. Possiamo considerare il caso in cui i dati ottenuti vengono semplicemente
scartati (es. instradati in /dev/null) onde semplificare l’analisi.
Per effettuare gli esperimenti sono stati costruiti due programmi di test. Un programma che
svolgerà il ruolo del client ed un altro quello del server. Ambedue i programmi tramite i
parametri a linea di comando sono configurabili in base alla:
• porta TCP sulla quale il server sarà in ascolto ovvero il client tenterà di connettersi
• formula utilizzata per le connessioni in caso di una sessione di registrazione
• nel caso del client, l’indirizzo (ip o web) dove il server risiede
Sia il programma client che quello server sono stati sviluppati sia per il sistema operativo
Linux (dove le modifiche tcp sono state apportate) e Windows 7.
3.1 Impatto modifiche apportate allo stack
TCP
Analizzare l’impatto dovuto all’utilizzo delle risorse (memoria, cpu, cache ..) di una
connessione TCP non è un’operazione semplice. Non è un processo sul quale tramite un
34
utility del SO (systat, sysprof) si può applicare un profiling. Proprio per questo motivo lo è
ancora di più fare un confronto tra i 2 kernel, quello modificato o non.
E’ importante però, che le modifiche apportate non introducano alcun ritardo significativo
sul normale funzionamento dello stack TCP. Quindi è stato istituito un ambiente di test
dove l’unica variabile è l’implementazione del kernel onde poter sostenere che l’impatto
introdotto dalle modifiche sia accettabile.
Ambiente di test
Un kernel non modificato ospitato in una VirtualBox, A. Un kernel modificato in una
seconda VirtualBox, B. Su ognuno dei kernel, modificato e non, va in esecuzione
un’istanza dello stesso programma client. Un server C in ascolto sulla porta 80, situato
nella stessa macchina dove le macchine virtuali ospitanti i due kernel oggetto di studio
vanno in esecuzione.
Figura 3.1 Ambiente di test. Macchina A (Vbox): kernel NON modificato; macchina B (Vbox): kernel modificato;
macchina C: server in ascolto, in esecuzione sulla macchina ospite (Windows7)
35
Come si può intuire dalla figura, l’unica variabile è il kernel. Il mezzo fisico di
comunicazione tra i client ed il server è lo stesso. Essendo che il mezzo fisico in questo
caso è la memoria, esso non introduce alcuna variabile al nostro ambiente.
Operazione
Nei kernel oggetto di valutazione, vanno in esecuzione simultaneamente i client che
effettuano dei file upload verso il server in ascolto sulla porta 80. Gli upload vengono
eseguiti in modo sequenziale; la dimensione dei file è fissa, 463917280 bytes; il numero totale
di upload effettuati è 60. Per ogni upload viene tenuta traccia del tempo impiegato. Alla
fine di questa serie di upload viene trovata una media del tempo impiegato. In conclusione
viene effettuato un confront tra I due kernel, in base alla media di upload. Ci si aspetta che
la differenza tra le due medie non sia significativa.
Risultati
Vengono riportati in seguito i risultati del test di cui sopra. Nel grafico seguente viene
tracciata la durata per ogni upload effettuato da ognuno dei client in esecuzione sui kernel
oggetto di confronto.
Figura 3.2 Confronto in base alla “durata di upload”
36
La tabella seguente riassume la media e la durata complessiva di upload per i due kernel in
confronto.
Kernel NON modificato Kernel modificato
durata media upload (sec) 155.2 155.56
somma totale durata upload (sec) 9328.07 9334.01
Come dai risultati si evince, non vi è alcun ritardo significativo. Mediamente per ambedue
i campioni le grandezze, media e somma, sono praticamente uguali.
3.2 Impatto sessione di registrazione
Una sessione di registrazione attiva, trascurando per semplicità l’elaborazione dei dati in
contesto utente, comporta le seguenti operazioni:
• memorizzazione dei valori RTT e RTO nelle opportune strutture dati
• esportazione dei dati tra il contesto kernel e quello utente
Tali operazioni implicano per prima un consumo di memoria: i buffer creati dove i valori
RTT e RTO verranno memorizzati. Essendo l’esportazione attuata con il memory
mapping, la memoria allocata sarà la stessa dall’inizio alla fine della sessione, perciò la
possiamo considerare una costante della nostra funzione impatto. Quindi rimane solamente
il consumo di CPU.
Possiamo però, misurare l’impatto di una sessione di registrazione facendo un confronto
tra due campioni di connessioni TCP. Il primo campione viene da un kernel modificato e
sul quale non viene attuata alcuna sessione di registrazione. Il secondo campione viene
ugualmente da un kernel modificato sul quale però, una sessione di registrazione viene
attuata. Per entrambi i campioni la formula utilizzata è la stessa. In entrambi i casi
verranno effettuati una serie di file upload verso un server.
37
Ambiente di test
L’esperimento è simile a quello precedentemente descritto nel paragrafo 3.1. A differenza
di prima, in questo caso in ambedue le macchine virtuali vi è in esecuzione un kernel
modificato. Inoltre, il client in esecuzione sul kernel ospitato nella VirtualBox B attua una
sessione di registrazione.
Operazione
L’esperimento è stato condotto esattamente come quello precedente, descritto nel
paragrafo 3.1.
Figura 3.3 Ambiente di test . Macchina A (Vbox): kernel modificato; macchina B (Vbox): kernel modificato sessione di
registrazione in atto; macchina C: server porta 80 in locale
Risultati
Vengono riportati in seguito i risultati del test di cui sopra. Nel grafico seguente viene
tracciata la durata per ogni upload effettuato da ognuno dei client in esecuzione sui kernel
in confronto.
38
Figura 3.4 Confronto in base alla “durata di upload”
La tabella seguente riassume la media e la durata complessiva di upload per i due kernel in
confronto.
Kernel modificato Kernel modificato + sessione rto
durata media upload (sec) 155.9 156.04
somma totale durata upload (sec) 9354.31 9356.72
Come dai risultati si evince, anche in questo caso non vi è alcun ritardo significativo.
Mediamente per ambedue i campioni le grandezze, media e somma, sono praticamente
uguali.
39
4. CASI DI STUDIO
Per rendere meglio l’idea di cosa offre e di come si può utilizzare l’infrastruttura proposta
sono stati presi in considerazione due casi di studio. Nel primo caso si tratta di una formula
già oggetto di ricerca (vedasi Referenze, [5]): ci si aspetta che i risultati ottenuti siano
allineati con quanto in letteratura riportato. Il secondo caso riguarda una seconda formula
di test, preparata al solo fine di dimostrare la flessibilità dello strumento proposto.
L’iter procedurale per ognuno dei casi, è il seguente:
• implementare un modulo kernel per l’aggiornamento dinamico di RTO, come la
formula oggetto di studio specifica
• effettuare, simultaneamente sulla stessa macchina virtuale col kernel modificato,
sia utilizzando la formula oggetto di studio che quella standard, una serie di file
upload, per ognuno dei quali attuare lato client una sessione di registrazione
• effettuare, solamente per il primo caso di studio, simultaneamente sulla stessa
macchina virtuale col kernel modificato, sia utilizzando la formula oggetto di
studio che quella standard, una serie di file download per ognuno dei quali attuare
lato server una sessione di registrazione
• confrontare il campione ottenuto con la formula oggetto di studio con quello della
standard, in base alle seguenti variabili:
o tempo medio di upload/download
o tempo totale (per l’intero campione) di upload/download
o numero di SYN inviati nella fase 3WHS (solamente per il primo caso di
studio)
o numero di RTO scaduti successivamente alla fase 3WHS (solamente per il
secondo caso di studio)
o numero di connessioni outgoing non riuscite
o ‘densità di probabilità’ funzione di ‘tempo upload/download’
o ‘distribuzione cumulativa’ funzione di ‘tempo upload/download’
40
Per tutti gli esperimenti seguenti il numero dei ‘file upload/download’ è 60. La dimensione
del file varia, pertanto sarà specificato per ogni esperimento. Per i file upload è stato
implementato un programma client, il quale attua una sessione di registrazione. Per i file
download invece, è stato implementato un programma server, il quale attua una sessione di
registrazione. Quindi è importante che, solo dal lato dove la sessione di registrazione viene
attuata vi sia in esecuzione il kernel modificato. Per quanto riguarda la controparte è
indifferente: infatto in uno degli scenari seguente la controparte è un sito web.
Per quanto riguarda la ‘densità di probabilità’ e la ‘distribuzione cumulativa’ è stato
considerato il caso della distribuzione normale con media il mediano (Excel - MEDIAN), e
come varianza il quadrato della deviazione standard (Excel - STDDEV).
In seguito i termini outgoing e incoming verranno utilizzati per distinguere le connessioni
TCP come segue:
• outgoing
connessione TCP in uscita, risultato di una syscall connect (caso tipico di un client
che si collega ad un server)
• incoming
connessione TCP in ingresso, risultato di una syscall accept (caso tipico di un
server che accetta in ingresso una connessione da parte di un client)
4.1 Formula ‘chu’
In questo caso di studio è stata analizzata la formula per l’aggiornamento dinamico di RTO
proposta da H.K. Jerry Chu (vedasi Referenze, [5]). In particolare, l’unica modifica
proposta rispetto alla formula standard consiste nel valore iniziale di RTO al momento in
cui viene iniziato il protocollo di apertura connessione.
41
La formula standard per l’aggiornamento dinamico di RTO è riportata in (rfc2988) ed
omessa da questo documento per brevità. La formula implementa un algoritmo sviluppato
da Van Jacobson nel 1988 ed utilizzato da allora in tutte le implementazioni di TCP. Il
documento rfc2988 specifica alcuni dettagli realizzativi necessari per l’applicazione pratica
dell’algoritmo di Van Jacobson.
In particolare, rfc2988 specifica che il valore iniziale per RTO quando non sono disponibili
misure di RTT è 3 s. La formula analizzata in questa sezione invece assume come valore
iniziale per RTO 1 s. Inoltre, a differenza di quella standard, allo scadere del 1° timeout di
ricezione, il valore di RTO rimane invariato.
Osservazioni sulla formula rto oggetto di studio
La motivazione di questa scelta, secondo l’autore, è riassunta nei seguenti punti:
• le reti moderni attuali sono più veloci (rispetto al momento in cui il valore iniziale di
RTO è stato impostato)
• studi (effettuati dallo stesso autore) dimostrano che il valore di RTT nel 97.5% delle
connessioni in un test a larga scala è minore di 1 secondo
• studi osservano che la percentuale di RTO scaduti nella fase 3WHS (3-way handshake)
è intorno al 2% (un valore di certo non trascurabile)
• per il 2.5% delle connessioni con un valore di RTT maggiore di 1 secondo, la formula
garantisce un rinvio (SYN or SYNACK) sia esso necessario o meno
Secondo le osservazioni dell’autore, la formula per l’aggiornamento dinamico di RTO
risulta utile nelle connessione a vita breve, per le quali il tempo di 3WHS è una
componente non trascurabile. E’ il caso tipico delle pagine html: esse sono composte da un
insieme di risorse tipicamente di piccole dimensioni. La durata di caricamento della pagina
html è il tempo della durata di caricamento massima tra quelle di ognuna delle risorse.
Pertanto diminuire la durata della fase 3WHS, nel caso essa sia comparabile con la durata
totale del trasferimento è importante.
42
4.1.1 Connessioni outgoing
Per le connessioni outgoing vengono effettuati una serie di file upload verso un server
TCP - porta 80. Per ogni connessione viene attuata una sessione di registrazione.
Scenario 1
Figura 4.1 Ambiente di test
Vengono considerati più di un caso in base all’ubicazione del server, al valore iniziale di
RTO (rto_3whs) ed al layer di disturbo (tc) introdotto. Ognuno dei casi comporterà dei test
sia con la formula oggetto di studio che quella standard. Infine in base ai risultati ottenuti si
cercherà di trarre delle conclusioni.
La seguente figura riporta un confronto tra i campioni ottenuti con la formula standard e
quella oggetto di studio in base alla ‘durata upload’. Il grafico del numero dei ‘syn inviati’
necessari per stabilire la connessione viene omesso, in quanto i valori sono uguali a 1, tra
le due formule, per ogni upload.
43
Figura 4.2 Confronto in base alla “durata di upload”
Segue il confronto tra i campioni ottenuti con la formula standard e quella oggetto di
studio, in base alla ‘densità di probabilità’ e ‘distribuzione cumulativa’, ambedue funzione
della ‘durata di upload’.
Figura 4.3 Confronto in base alla “densità di probabilità” e “distribuzione cumulativa”
La tabella seguente riassume la media, la durata complessiva, il numero medio di syn
inviati ed il numero di connessioni non riuscite per i campioni messi a confronto.
standard: rto_3whs = 3000msec chu: rto_3whs = 1000msec
durata media upload (sec) 0.55 0.56
somma totale durata upload (sec) 33.17 33.64
44
media syn inviati 1 1
connessioni non riuscite 0 0
dimensione file 99399 99399
I risultati non riportano alcuna notevole differenza. Nessun timeout scaduto per un
pacchetto SYN e nessuna connessione non riuscita. Il valore iniziale RTO per la formula
oggetto di studio nonostante sia 3 volte più piccolo di quella standard è comunque
abbastanza alto. Infatti in base a registrazioni precedenti, il primo valore registrato RTT
(~50 msec) è ampiamente minore di quello iniziale RTO (1000 msec).
Scenario 2
Lo scenario è identico al precedente tranne che per il valore iniziale di RTO che a
differenza di prima è di 100 msec.
La seguente figura riporta il confronto tra i campioni ottenuti con la formula standard e
quella oggetto di studio in base alla ‘durata di upload’ e del numero dei ‘syn inviati’
necessari per stabilire la connessione.
Figura 4.4 Confronto in base alla “durata di upload” e “syn inviati”
45
La formula per l’aggiornamento dinamico di RTO oggetto di studio comporta dei rinvii di
pacchetti SYN, mentre molto probabilmente l’ACK era in dirittura d’arrivo. Questi rinvii
penalizzano anche la stessa durata di upload. Va detto però che il valore iniziale RTO è
stato scelto all’incirca il doppio del 1° valore RTT (risultato di precedenti sessioni di
registrazione), come un caso limite appositamente per osservarne gli effetti.
Invece la seguente figura riporta un confronto tra i campioni ottenuti con la formula
standard e quella oggetto di studio in base alla ‘densità di probabilità’ e ‘distribuzione
cumulativa’, ambedue funzione della ‘durata di upload’.
Figura 4.5 Confronto in base alla “densità di probabilità” e “distribuzione cumulativa”
Il grafico riguardante la ‘densità di probabilità’ dimostra che il campione proveniente da
sessioni con la formula oggetto di studio nonostante abbia una media quasi uguale, è più
sparso rispetto a quello della formula standard. Infatti i valori troppo distanti dalla media
appartengono appunto a questo campione (tracciato color rosso).
La tabella seguente riassume la media, la durata complessiva, il numero medio si syn
inviati ed il numero di connessioni non riuscite per i campioni messi a confronto.
standard: rto_3whs = 3000msec chu: rto_3whs = 100msec
46
durata media upload (sec) 0.55 0.67
somma totale durata upload (sec) 33.4 40.45
media syn inviati 1 1.06
connessioni non riuscite 0 0
dimensione file 99399 99399
Scenario 3
Figura 4.6 Ambiente di test
Nello scenario di un server situato nella macchina host e dove sul kernel è stato attivato un
layer di disturbo (tc) i risultati sono diversi in confronti a quelli precedenti.
47
Figura 4.7 Confronto in base alla “durata di upload” e “syn inviati”
Si nota anche in questo caso un rinvio di pacchetti SYN più frequente per le connessioni
che utilizzano la formula oggetto di studio. A differenza della formula standard però, esso
reagisce più velocemente ad eventuali disturbi introdotti dal layer tc.
Segue il confronto tra i campioni ottenuti con la formula standard e quella oggetto di studio
in base alla ‘densità di probabilità’ e ‘distribuzione cumulativa’, ambedue funzione della
‘durata upload’. Anche in questo caso il campione proveniente da sessioni con la formula
oggetto di studio è più sparso. In compenso però la campana è centrata leggermente più a
sinistra di quella standard, indicando quindi una durata di upload media minore.
48
Figura 4.8 Confronto in base alla “densità di probabilità” e “distribuzione cumulativa”
La tabella seguente riassume la media, la durata complessiva, il numero medio si syn
inviati ed il numero di connessioni non riuscite per i campioni messi a confronto.
standard: rto_3whs = 3000msec chu: rto_3whs = 100msec
durata media upload (sec) 0.91 0.88
somma totale durata upload (sec) 54.67 53.24
media syn inviati 1 1.26
connessioni non riuscite 4 0
dimensione file 99399 99399
Dal confronto tra i due campioni, nello scenario con un layer di disturbo, vanno sottolineati
i seguenti punti:
• la formula standard necessità 4 connessioni in più rispetto a quella oggetto di studio
• la media dei SYN, inviati prima che la connessione sia stabilita, per la formula
oggetto di studio è maggiore di quella standard
49
• la media di ‘durata di upload’ per la formula oggetto di studio è minore di quella
standard
• la ‘durata totale’ dell’intero campione proveniente dalla formula oggetto di studio
è minore di quella standard
La maggiore durata ‘totale’ e ‘media’ nel caso della formula standard in parte è
dovuta anche a:
o l’informazione, sull’eventuale 2° pacchetto SYN non ancora confermato,
viene recuperata più tardi nel caso della formula standard (ricordiamo che
per la formula oggetto di studio, RTO rimane invariata al 1° timeout di
ricezione scaduto invece di crescere esponenzialmente come nel caso della
formula standard)
4.1.2 Connessioni incoming
Per le connessioni incoming vengono effettuati una serie di file download da parte di un
server tcp. Vengono eseguiti simultaneamente due applicativi server in una VirtualBox
ospitante un kernel modificato. Uno dei server utilizzerà la formula standard, invece l’altro
quella oggetto di studio per le connessioni accettate in ingresso. In ambiente Windows (dove la
VirtualBox viene ospitata) saranno messi in esecuzione due client che si connetterano ai server
effettuando quindi l’upload di un file di dimensione fissa.
Per ogni connessione accettata in ingresso ambedue i server attueranno una sessione di
registrazione. Il motivo della sessione non è tanto per i valori di RTT e RTO (infatti i server
solamente ricevono dati), se non per il numero di RTO scaduti durante la fase iniziale della
connessione. Al kernel modificato è stato applicato un layer tc che simula in qualche modo un
ambiente quanto più simile a quello reale.
La figura seguente riporta il confronto tra i campioni ottenuti con la formula standard e
quella oggetto di studio in base alla ‘durata di download’ ed al numero di ‘synack inviati’
necessari per stabilire la connessione.
50
Figura 4.9 Confronto in base alla “durata di download” e “synack inviati”
In questo scenario i grafici della ‘durata di download’ sono molto simili nonostante le
oscillazioni. Va sottolineato il fatto che il campione proveniente da sessioni con la formula
oggetto di studio ha in media un numero di pacchetti SYNACK inviati maggiore (superiore
a 2) rispetto a quella standard.
La seguente figura invece, riporta un confronto tra i campioni ottenuti con la formula
standard e quella oggetto di studio in base alla ‘densità di probabilità’ ed alla
‘distribuzione cumulativa’ ambedue funzione della ‘durata di upload’. Essa conferma il
fatto che i due campioni sono molto simili sia dal punto di vista della media che della
varianza.
51
Figura 4.10 Confronto in base alla “densità di probabilità” e “distribuzione cumulativa”
La tabella seguente riassume la media, la durata complessiva ed il numero medio si synack
inviati per i campioni messi a confronto. In questo scenario non è possibile conoscere il
numero delle connessioni non riuscite in quanto nel lato server questa informazione manca
ovvero le uniche connessioni di cui abbiamo traccia sono quelle accettate.
standard: rto_3whs = 3000msec chu: rto_3whs = 100msec
durata media download (sec) 4.12 4.05
somma totale durata download (sec) 247.22 243.1
media synack inviati 1.03 2.16
connessioni non riuscite non nota non nota
dimensione file 99399 99399
Dal confronto tra i due campioni vanno sottolineati i seguenti punti:
• la formula oggetto di studio comporta un numero di pacchetti SYNACK inviati
maggiore rispetto a quella standard
• il tempo impiegato per l’invio del file è più breve nel caso della formula oggetto di
studio
52
4.1.3 Riassunto ed osservazioni
La tabella seguente riporta il riassunto dei risultati, per ogni esperimento effettuato.
Figura 4.11 Riassunto risultati
Di primo impatto può sembrare che la formula oggetto di studio sia controproducente, ma
ha pure i suoi punti di forza:
• nell’eventualità di un server non presente la connessione viene chiusa prima
essendo i tentativi di retry col rinvio del pacchetto SYN limitati, essi verranno
esauriti prima rispetto ad un caso con un valore iniziale RTO più alto. Nel caso di
un server web questo vorrebbe dire che risorse preziose vengono rilasciate il prima
possibile
53
• nell’eventualità di una perdita di pacchetti il loro rinvio è più veloce
nel caso i pacchetti vadano persi un rinvio degli stessi avrà luogo prima, con
conseguenza un eventuale trasferimento più veloce. D’altra parte però, se i
pacchetti non sono persi, ma in dirittura d’arrivo questo implicherebbe della banda
occupata inutilmente. Ma se consideriamo il caso di un trasferimento dati di piccole
dimensioni (risorse pagine web) l’aumento d’occupazione della banda può essere
accettabile in compenso di un tempo di trasferimento più breve
• per percorsi specifici il primo valore RTT di una sessione di registrazione può
servire come base per il valore iniziale RTO
nel caso si volesse modellare l’andamento di RTO per un percorso o per un
intervallo giornaliero particolare verso un endpoint specifico, informazioni
ottenute da precedenti sessioni di registrazione possono tornare molto utili. Il primo
valore RTT registrato da una sessione attuata può servire come un punto di
partenza per impostare quello iniziale di RTO. Ovviamente un valore iniziale
RTO uguale a quello RTT comporterebbe un rinvio di pacchetti ‘aggressivo’.
Invece multipli del valore iniziale di RTT, a partire dal 2, potrebbe dare una
migliore prestazione delle connessioni verso quel endpoint.
4.2 Formula ‘speedy’
Il secondo caso di studio riguarda una formula per l’aggiornamento dinamico di RTO che
utilizza la seguente regola:
RTOi = (RTTi * α) + (RTTi-1 * β) + (RTTi-2 * γ) + (RTOi-1 * θ) dove:
• i indica il valore corrente, i-1 quello precedente e cosi via
• α,β,γ,θ costanti
54
Essa è funzione degli ultimi 3 valori di RTT e dell’ultimo valore di RTO. La componente
RTO è utile particolarmente nel caso in cui non vi è più alcun aggiornamento sui valori di
RTT (ovvero nessun ACK in arrivo). In mancanza di questa componente, la RTO
rimarrebbe invariata, quando invece è ragionevole che la mancanza di ACK sia una chiara
indicazione che la RTO vada aumentata.
La seguente figura fornisce un idea sull’ambiente in cui gli esperimenti sono stati svolti. A
differenza degli scenari con la formula ‘chu’, in questa sezione saranno considerati
solamente le connessioni outgoing.
Figura 4.12 Ambiente di test
Inoltre, oggetto di confronto tra le due formule saranno gli ‘rto scaduti’ piuttosto che gli
‘syn inviati’, in quanto più significativi.
L’unica differenza tra i seguenti scenari sarà la formula stessa. Modificando
opportunamente le costanti di cui sopra è possibile avere formule anche molto diverse.
Infatti per gli esperimenti seguenti verranno utilizzati valori differenti proprio per
55
evidenziare sia situazioni ‘normali’ che casi limite.
4.2.1 Connessioni outgoing
Scenario 1
In questo scenario i valori delle costanti sono:
α = 1, β = 0.5, γ = 0.25, θ = 0.5 quindi la formula è:
RTOi = RTTi + (RTTi-1 / 2) + (RTTi-2 / 4) + (RTOi-1 / 2)
La seguente figura riporta il confronto tra i campioni ottenuti con la formula standard e
quella oggetto di studio in base alla ‘durata di upload’ e dei ‘rto scaduti’.
Figura 4.13 Confronto in base alla “durata di upload” e “rto scaduti”
Aparte occasionali differenze, in media sia la ‘durata di upload’ che gli ‘rto scaduti’ tra le
due formule sono praticamente uguali.
56
Segue il confronto tra i campioni ottenuti con la formula standard e quella oggetto di studio
in base alla ‘densità di probabilità’ e ‘distribuzione cumulativa’, ambedue funzione della
‘durata upload’.
Figura 4.14 Confronto in base alla “densità di probabilità” e “distribuzione cumulativa”
Il grafico della ‘densità di probabilità’ conferma il fatto che ambedue i campioni hanno
media quasi uguale. Infatti le loro campane sono quasi centrate nello stesso punto. La
varianza del campione della formula oggetto di studio ha un valore minore, motivo per cui
il relativo grafico di ‘densità di probabilità’ è meno schiacciato di quello standard.
La tabella seguente riassume la media, la durata complessiva, il numero medio di rto
scaduti ed il numero di connessioni non riuscite.
standard: rto_3whs = 3000msec speedy: rto_3whs = 100msec
durata media upload (sec) 177.24 174.987
somma totale durata upload (sec) 10634.43 10499.24
media rto scaduti 67.5 71.5
connessioni non riuscite 0 0
dimensione file 1372160 1372160
57
Scenario 2 In questo scenario i valori delle costanti sono:
α = 1, β = 0.25, γ = 0.125, θ = 0.125 quindi la formula è:
RTOi = RTTi + (RTTi-1 / 4) + (RTTi-2 / 8) + (RTOi-1 / 8)
Rispetto allo scenario precedente i valori RTO calcolati sono in media minori. Questo
implica che il numero di eventuali ritrasmissioni di un pacchetto o insieme di, non ancora
confermato, sarà maggiore. Si può dire che suddetta formula è ‘aggressiva’ in quanto
molto sensibile ad eventuali ritardi nella ‘conferma dell’avvenuta ricezione’.
La seguente figura riporta il confronto tra i campioni ottenuti con la formula standard e
quella oggetto di studio in base alla ‘durata di upload’ e del numero dei ‘rto scaduti’.
Figura 4.15 Confronto in base alla “durata di upload” e “rto scaduti”
Il grafico di ‘durata di upload’ dimostra in maniera evidente come la formula oggetto di
studio effettua il trasferimento dei file in un tempo mediamente minore. Questo risultato
58
arriva a discapito della banda: infatti il numero dei RTO scaduti, quindi delle ritrasmissioni
è maggiore rispetto alla formula standard.
La seguente figura riporta il confronto tra i campioni ottenuti con la formula standard e
quella oggetto di studio in base alla ‘densità di probabilità’ e ‘distribuzione cumulativa’,
ambedue funzione della ‘durata upload’. In linea con quanto scritto poc’anzi si nota come
la campana nel caso della formula oggetto di studio si trova alla sinistra di quella standard.
Figura 4.16 Confronto in base alla “densità di probabilità” e “distribuzione cumulativa”
La tabella seguente riassume la media, la durata complessiva, il numero medio di rto
scaduti ed il numero di connessioni non riuscite per i campioni messi a confronto.
standard: rto_3whs = 3000msec speedy: rto_3whs = 100msec
durata media upload (sec) 172.5962 163.1614
somma totale durata upload (sec) 10355.77 9789.681
media rto scaduti 66.85 118.58
connessioni non riuscite 0 0
dimensione file 1372160 1372160
59
Scenario 3 In questo scenario i valori delle costanti sono:
α = 1, β = 1, γ = 0.5, θ = 0.5 quindi la formula è:
RTOi = RTTi + RTTi-1 + (RTTi-2 / 2) + (RTOi-1 / 2)
Rispetto al 1° scenario, i valori RTO calcolati sono in media maggiori. Questo implica che
il numero di eventuali ritrasmissioni di un pacchetto o insieme di non ancora confermato,
sarà minore. Si può dire che suddetta formula è ‘lenta’ in quanto poco sensibile ad
eventuali ritardi nella ‘conferma dell’avvenuta ricezione’.
Figura 4.17 Confronto in base alla “durata di upload” e “rto scaduti”
Il grafico della ‘durata upload’ dimostra in maniera evidente come la formula oggetto di
studio effettua il trasferimento dei file in un tempo mediamente maggiore. In compenso
però il numero dei RTO scaduti è minore rispetto alla formula standard. Lo scenario
corrente è un altro caso limite, opposto a quello precedente.
La seguente figura riporta un confronto tra i campioni ottenuti con la formula standard e
quella oggetto di studio in base alla ‘densità di probabilità’ e ‘distribuzione cumulativa’,
60
ambedue funzione della ‘durata upload’. In linea con quanto scritto poc’anzi si nota come
la campana nel caso della formula oggetto di studio si trova alla destra di quella standard.
Figura 4.18 Confronto in base alla “densità di probabilità” e “distribuzione cumulativa”
La tabella seguente riassume la media, la durata complessiva, il numero medio di rto
scaduti ed il numero di connessioni non riuscite per i campioni messi a confronto.
standard: rto_3whs = 3000msec speedy: rto_3whs = 100msec
durata media upload (sec) 180.381 205.295
somma totale durata upload (sec) 10822.87 12317.73
media syn inviati 70.86 52.08
connessioni non riuscite 0 0
dimensione file 1372160 1372160
61
4.2.2 Riassunto ed osservazioni La tabella seguente riporta un riassunto dei risultati di ciascuno degli esperimenti effettuati.
Figura 4.19 Riassunto risultati
Come evidenziato in precedenza il motivo degli esperimenti di questa sezione è solamente
quello di utilizzare lo strumento proposto. Utilizzando una formula per il calcolo dinamico
RTO, funzione dei valori precedenti di RTT e RTO, opportunamente pesati, si è visto che
si possono ottenere diversi risultati. In particolare:
• utilizzando una formula ‘aggressiva’, in media i trasferimenti sono di durata
minore rispetto alla formula standard. Ovviamente a discapito della banda: un
numero maggiore di rto scaduti implica un numero maggiore di ritrasmissioni
62
• utilizzando una formula ‘lenta’, in media i trasferimenti sono di durata maggiore
rispetto alla formula standard. In compenso però si ha un occhio di riguardo alla
banda
• utilizzando una formula ‘equilibrata’, ovvero i cui valori RTO sono compresi tra il
minimo ed il massimo dei due scenari precedenti, in media i trasferimenti sono
simili alla formula standard
63
CONCLUSIONI
Oggetto di studio di questo elaborato è stato la realizzazione di un’infrastruttura per attuare
politiche alternative di ritrasmissione in TCP. Essendo esso un protocollo affidabile, il
trasferimento dei dati tra due endpoint deve essere garantito. Spesso i dati inviati oppure la
risposta stessa dell’avvenuta ricezione inviata dal ricevente vanno persi. Quindi allo
scadere di RTO, i dati non ancora confermati devono essere ritrasmessi. Tale processo
avviene appunto con delle politiche di ritrasmissione.
In linea con gli obiettivi prefissi è stata costruita l’infrastruttura seguente che consente di:
• ottenere informazioni sui valori di RTT e RTO relativi ad una connessione
• modificare la formula per l’aggiornamento dinamico di RTO: essa può essere
associata ad una singola connessione oppure a tutto il sistema
Con l’infrastruttura proposta è possibile modificare la formula per il calcolo di RTO e
testarne immediatamente gli effetti introdotti nella comunicazione, senza dover far ripartire
il sistema operativo, o tanto meno ricompilare il kernel. Inoltre volendo approfondire
ulteriormente l’analisi si può avere accesso ai valori RTT e RTO relativi ad una
connessione TCP.
Nella progettazione di questa infastruttura un occhio di riguardo in più è stato posto sulla
performance e la semplicità d’utilizzo. La performance non è intesa solamente come
prestazioni dal punto di vista della cpu, ma anche come “interferire il meno possibile” col
corso d’azione dello stack TCP. La semplicità d’utilizzo è importante in quanto un sistema
di test non può in alcun modo avere un tempo di set-up tale da renderlo inutilizzabile.
Una serie di test effettuati su campioni di connessioni TCP hanno evidenziato che
l’impatto delle modifiche apportate non ha in alcun modo compromesso il normale
funzionamento del kernel o le sue perfomance. Anche l’impatto delle sessioni di
registrazione attuate su connessioni TCP non interferisce sulle loro performance.
64
Con l’intenzione di dimostrare la semplicità e flessibilità d’utilizzo dello strumento
proposto sono stati presi in considerazione come casi di studio due formule per
l’aggiornamento dinamico di RTO: ‘chu’ e ‘speedy’. Nel primo caso si tratta di una
formula già oggetto di ricerca (vedasi Referenze Jerry Chu [5]), per la quale tra l’altro si è
verificato che i risultati sono in linea con quanto riportato in literatura. Il secondo caso
invece riguarda una formula di test pensata piuttosto come un ulteriore esempio.
Ovviamente l’infrastruttura in futuro richiederà modifiche e miglioramenti. Per iniziare,
ulteriori informazioni sulla connessione TCP, che durante l’utilizzo potrebbe nascere la
necessità di avere. Un ulteriore miglioramente è l’aggiornamento dinamico della formula
RTO in tempo reale, in funzione delle elaborazioni effettuate su sessioni di registrazione.
In tempo reale i valori RTT e RTO su specifiche connessioni, vengono elaborate ed il
risultato di questa elaborazione viene utilizzato per modificare la formula. Questo
ovviamente implica un’altra infrastruttura affiancata alla corrente. Alcuni possibili scenari
ove tale miglioramento può risultare utile sono:
• ottimizzare il trasferimento dei dati tra due reti aziendali divise da Internet, che si
adatta a possibili ritardi della rete (intervalli giornalieri, router intermedi non
funzionanti ecc)
• adeguarsi alle caratteristiche della rete nella quale un dispositivo mobile si muove
65
Referenze
[1] Gary R. Wright, Richard Stevens “Tcp/Ip illustrated, Volume 2: The
implementation”
[2] Daniel P. Bovet, Marco Cesati “Understanding Linux Kernel, 3rd Edition”
[3] Jonathan Corbet, Alessandro Rubini, and Greg Kroah-Hartman “Linux Device
Drivers 3rd Edition”
[4] Robert Love “Linux Kernel Development 2nd Edition”
[5] http://www.ietf.org/proceedings/75/slides/tcpm-1.pdf
[6] Nabil Seddigh “Performance analysis of TCP’s Retransmission Timeout
Mechanism”
[7] www. http://people.ee.ethz.ch/~arkeller/linux/kernel_user_space_howto.html
[8] http://www.linuxfoundation.org/collaborate/workgroups/networking/tcp_testing
[9] http://www.ibm.com/developerworks/library/j-zerocopy/
[10] http://www.mjmwired.net/kernel/Documentation/memory-barriers.txt
[11] http://www.mjmwired.net/kernel/Documentation/circular-buffers.txt
[12] http://www.mjmwired.net/kernel/Documentation/atomic_ops.txt
[13] http://blogs.arm.com/software-enablement/448-memory-access-ordering-part-2-
barriers-and-the-linux-kernel/
[14] http://www.mjmwired.net/kernel/Documentation/networking/packet_mmap.txt
[15] http://www.rossbencina.com/code/lockfree
[16] http://www.shorewall.net/traffic_shaping.htm
[17] http://lartc.org/howto/
[18] http://www.guyrutenberg.com/2007/09/22/profiling-code-using-clock_gettime/
66
Appendice
I file sorgente modificati e quelli nuovi sia a livello kernel che utente sono raggruppati in
un’unica directory, che a sua volta contiene le seguenti subdirectory:
• include
si trovano tutti i file header a livello kernel. In particolare si trovano i vari header
kernel modificati, ma anche quelli creati ex novo.
• net
si trovano tutti i file sorgente a livello kernel. In particolare si trovano i vari file
kernel modificati, ma anche quelli creati ex novo.
• tesi
si trova il resto dei file. Vi si trovano i vari moduli kernel, sia quello della formula
rto che quello della registrazione RTT e RTO. Infine si trovano anche tutti gli
applicativi a livello utente.
A. Installazione
La versione Linux utilizzata è la Slackware 13.1. Nel nostro caso per semplicità esso è
stato installato in una macchina virtuale, VirtualBox. Per ulteriori dettagli su come
installare la VirtualBox, quindi Slackware si riporta nei vari tutorial disponibili in rete. Una
volta installata la versione base si procederà con la compilazione del kernel ‘vanilla’,
versione 2.6.34.7. Prima della compilazione vanno riportate le modifiche necessarie: in
parte modifiche al codice esistente ed in parte l’aggiunta di file sorgenti e header. Dopo la
compilazione vanno modificate opportunamente i file di conf affinche al boot venga
proposto anche il nuovo kernel tra le opzioni.
Una volta effettuato il boot con il kernel modificato, verranno compilati i vari moduli
kernel. Quello riguardante la registrazione RTT e RTO e quello delle formule rto. Infine
67
verranno compilati lo skeleton e i programmi utilizzati per gli esperimenti: client e server.
In seguito verranno descritti più in dettaglio i passaggi tranne l’installazione della versione
Linux di base, per la quale si riporta nei vari tutorial disponibili in rete.
A.1 Upgrade del kernel
- decomprimere il kernel nella directory di destinazione
In questo caso la directory è “/usr/src/”.
tar -C /usr/src/ -xvf linux-2.6.34.7.tar.gz
cd /usr/src
rm linux
ln -s linux-2.6.34.7 linux
- copiare il file config esistente nella directory del nuovo kernel
zcat /proc/config.gz > /usr/src/linux/.config
cd linux-2.6.34.7
- preparare il file config
Il seguente comando ripercorrerà il file config esistente, utilizzandolo come configurazione
di partenza. Per funzionalità nuove chiederà l’intervento dell’operatore: almeno che non si
sappia esattamente cosa fare, si consiglia di confermare tutte le possibili scelte che a loro
volta sono quelle di default.
make oldconfig
- sovrascrivere i file del kernel 2.6.34.7 copiati in “/usr/src” con quelli modificati in questo
elaborato
In seguito vengono riportati i passi da seguire (si ricorda che /usr/src/linux-2.6.34.7 è la
directory dove il kernel nuovo è stato decompresso).
68
cp ./include/net/rtt_data.h /usr/src/linux-2.6.34.7/include/net/
cp ./include/net/rtt_sampling.h /usr/src/linux-2.6.34.7/include/net/
cp ./include/net/tcp.h /usr/src/linux-2.6.34.7/include/net/
cp ./include/net/sock.h /usr/src/linux-2.6.34.7/include/net/
cp ./include/net/request_sock.h /usr/src/linux-2.6.34.7/include/net/
cp ./include/net/Kbuild /usr/src/linux-2.6.34.7/include/net/
cp ./net/ipv4/Kconfig /usr/src/linux-2.6.34.7/net/ipv4/ NO
- aggiungere nel file “/usr/src/linux-2.6.34.7/net/ipv4/Kconfig”, fine pagina il seguente
contenuto:
menuconfig TCP_RTO_FORMULA_ADVANCED
bool "TCP: advanced rto formula"
###help###
Support for selection of various TCP rto formula
modules.
Nearly all users can safely say no here, and a safe default
selection will be made (default rot formula as a fallback).
if TCP_RTO_FORMULA_ADVANCED
config TCP_RTO_FORMULA_CASA
tristate "TCP Rto casa"
depends on EXPERIMENTAL
default y
###help###
Formula default calcolo RTO
choice
prompt "Default TCP rto formula"
default TCP_RTO_FORMULA_CASA
help
Select the TCP rto formula that will be used by default
for all connections.
config DEFAULT_CASA
bool "casa"
endchoice
69
endif
config TCP_RTO_FORMULA_CASA
tristate
depends on !TCP_RTO_FORMULA_ADVANCED
default y
config DEFAULT_TCP_RTO_FORMULA
string
default "casa"
- aggiungere al file “/usr/src/linux-2.6.34.7/net/ipv4/Makefile”:
a) obj-y: …
tcp_rto_formula.o rtt_sampling.o \ b) fine pagina obj-$(CONFIG_TCP_RTO_FORMULA_CASA) += tcp_rto_casa.o cp ./net/ipv4/rtt_sampling.c /usr/src/linux-2.6.34.7/net/ipv4/ cp ./net/ipv4/sysctl_net_ipv4.c /usr/src/linux-2.6.34.7/net/ipv4/ cp ./net/ipv4/tcp.c /usr/src/linux-2.6.34.7/net/ipv4/ cp ./net/ipv4/tcp_input.c /usr/src/linux-2.6.34.7/net/ipv4/ cp ./net/ipv4/tcp_ipv4.c /usr/src/linux-2.6.34.7/net/ipv4/ cp ./net/ipv4/tcp_output.c /usr/src/linux-2.6.34.7/net/ipv4/ cp ./net/ipv4/tcp_rto_casa.c /usr/src/linux-2.6.34.7/net/ipv4/ cp ./net/ipv4/tcp_rto_formula.c /usr/src/linux-2.6.34.7/net/ipv4/ cp ./net/ipv4/tcp_timer.c /usr/src/linux-2.6.34.7/net/ipv4/ cp ./net/ipv4/inet_connection_sock.c /usr/src/linux-2.6.34.7/net/ipv4/ cp ./net/ipv4/tcp_minisocks.c /usr/src/linux-2.6.34.7/net/ipv4/ cp ./net/core/sock.c /usr/src/linux-2.6.34.7/net/core/ ln -s /usr/src/linux-2.6.34.7/include/net/rtt_data.h /usr/include/net/rtt_data.h - compilazione cd /usr/src/linux-2.6.34.7 make menuconfig Attenzione: selezionare Networking support ---> Networking options ---> TCP: advanced rto formula (NEW) --->
assicurarsi di check-arlo (verrà selezionata la formula rto di default ‘casa’)
70
alla fine prima di Exit salvare, rispondendo ‘yes’
make bzImage modules
L’operazione può richiedere 1 ora o più in base alla potenza del processore ed anche della
configurazione stessa
make modules_install
- posizionare opportunamente i kernel nuovi appena compilati
cp arch/x86/boot/bzImage /boot/vmlinuz-rtt-2.6.34.7
cp System.map /boot/System.map-rtt-2.6.34.7
cp .config /boot/config-custom-2.6.34.7
- modificare opportunamente i riferimenti simbolici ai file di config e mappa dei simboli
cd /boot
rm config
ln -s config-custom-2.6.34.7 config
rm System.map
ln -s System.map-rtt-2.6.34.7 System.map
- creare il file di init
Sostituire /dev/sda2 come dal caso voluto
mkinitrd -c -k 2.6.34.7-smp -m mbcache:jbd:ext4 -f ext4 -r /dev/sda2
- aggiungere alla fine di /etc/lilo.conf
image = /boot/vmlinuz-rtt-2.6.34.7
root = /dev/sda2
label = Linux-rtt
read-only
addappend = "rootfstype=ext4"
71
- eseguire lilo affinche le modifiche abbiano luogo
lilo
Una volta fatto ripartire il kernel, compilare ogni subdirectory per verifica. Una volta che
la compilazione va a buon fine aggiungere in /etc/modules/rc.modules-2.6.33.4-smp, le
seguenti righe per installare al boot i device e caricare i moduli in automatico:
# loading our modules
if [ "$RELEASE" = "2.6.34.7#smp" ]; then
insmod /lib/modules/2.6.34.7#smp/rtto.ko
mknod /dev/rtto0 c 245 0
mknod /dev/rtto1 c 245 1
mknod /dev/rtto2 c 245 2
mknod /dev/rtto3 c 245 3
chgrp "root" /dev/rtto[0#3]
chmod 766 /dev/rtto[0#3]
fi
if [ "$RELEASE" = "2.6.34.7#smp" ]; then
insmod /lib/modules/2.6.34.7#smp/rto_chu.ko
fi
if [ "$RELEASE" = "2.6.34.7#smp" ]; then
insmod /lib/modules/2.6.34.7#smp/speedy.ko
fi
- ricompilazione
make bzImage modules
make modules_install
cp arch/x86/boot/bzImage /boot/vmlinuz-rtt-2.6.34.7
cp System.map /boot/System.map-rtt-2.6.34.7
cd /boot
mkinitrd -c -k 2.6.34.7-smp -m mbcache:jbd:ext4 -f ext4 -r /dev/sda2
lilo
72
B. Modifiche apportate nel kernel
Le modifiche apportate nel kernel riguardano sia le strutture dati che il codice stesso. Per
quanto riguarda le strutture si tratta sia di quelle nuove che delle modifiche a quelle già
esistenti con le quali sono associate. Nel codice si tratta di modifiche apportate al codice
esistente ma anche di codice inserito ex novo.
B.1 Struttura tree modificato
In seguito viene riportata parte della struttura tree del sorgente kernel evidenziando
solamente le modifiche e file nuovi aggiunti (seguiti da *).
… include net request_sock.h
rtt_data.h* rtt_sampling.h* sock.h tcp.h Kbuild
net core sock.c ipv4 inet_connection_sock.c
rtt_sampling.c*
sysctl_net_ipv4.c
tcp.c
tcp_input.c
tcp_ipv4.c tcp_minisocks.c tcp_output.c tcp_rto_casa.c* tcp_rto_formula.c* tcp_timer.c
Kconfig
Makefile
73
Segue il nome del file di configurazione dove tipicamente risiede del codice che si occupa
di far partire automaticamente servizi e/o applicativi. Nel caso in questione sono stati
aggiunti i moduli kernel sia quello per la registrazione RTT e RTO che le varie formula rto
utilizzate negli esperimenti.
/etc/modules/rc.modules-2.6.33.4-smp
B.2 Strutture nuove aggiunte
Strutture aggiunte nel kernel come supporto alla nuova infrastruttura.
./include/net/rtt_data.h
In esso vi sono definite le strutture basi, contenitori dei dati registrati nel contesto kernel.
Essendo il passaggio dei dati tra i due contesti perfezionato con il memory mapping, tali
strutture sono visibili anche nel contesto utente.
La seguente struttura viene utilizzata per il passaggio del campione RTT e RTO dallo stack
TCP all’infrastruttura proposta.
struct zsample
{
__u32 rtt;
__u32 rto;
long jiff_secs;
long jiff_nsecs;
__u8 type;
};
La struttura precedente non è un ottimo candidato per diventare l’elemento di un array. In
un architettura a 32 bit, il campo type, consumerebbe inutilmente 3 byte. La situazione
peggiora ulteriormente nel caso di un architettura a 64 bit. Ecco quindi la necessità dei
primi 5 campi della struttura seguente. I successivi campi, filled e emptied, sono utili al
produttore (chi aggiunge i dati) ed il consumatore (chi consuma i dati). I loro valori sono
intesi nel range [0 : BUFF_LEN - 1], indicando quindi l’elemento dell’array su cui sta
74
lavorando, rispettivamente il produttore ed il consumatore.
struct zsample_buffer
{
__u32 rtts[BUFF_LEN];
__u32 rtos[BUFF_LEN];
long jiff_secs[BUFF_LEN];
long jiff_nsecs[BUFF_LEN];
__u8 types[BUFF_LEN];
__u32 filled;
__u32 emptied;
};
La seguente struttura raggruppa un insieme delle strutture appena descritta. I campi
filled_buffs e emptied_buffs, i cui valori sono intesi nel range [0 : BUFFERS - 1] si riferiscono
all’elemento dell’array buffs, su cui sta lavorando, rispettivamente il produttore e il
consumatore. Il campo overruns, modificato in scrittura solamente dal produttore, viene
incrementato quando esso sovvrascrive un array sul quale il consumatore sta lavorando. E’
compito del consumatore accorgersi di questa evenienza, quindi comportarsi di
conseguenza.
struct zsample_buffer_holder
{
struct zsample_buffer buffs[BUFFERS];
__u32 filled_buffs;
__u32 emptied_buffs;
__u32 overruns;
};
./include/net/rtt_sampling.h
struct zsample_sniff_session
{
struct zsample_buffer_holder data;
int (*take_sample) (struct sock *sk, struct zsample val);
__u32 stack_done;
__u32 module_release_data_called;
75
long secs_from_epoch;
struct sock *sk;
void *private_data;
u32 zsynacks_sent;
u32 zsyn_sent;
};
• data : struttura dove i valori RTT e RTO vanno memorizzati
• take_sample : puntatore alla funzione che instrada il corso d’azione al modulo per la
registrazione di RTT e RTO
• stack_done : un flag inizialmente a 0 il cui valore viene cambiato a 1 dal processo di
rilascio delle risorse una volta che la connessione TCP a cui e associato viene
chiusa. Da quel momento, la struttura appartenente non sarà più referenziata dallo
stack TCP
• module_release_data_called : un flag inzialmente a 0 il cui valore viene cambiato a 1
dal modulo alla fine di una sessione di registrazione. Da quel momento la struttura
appartenente non sarà più referenziata dal modulo delle sessioni di registrazione
• secs_from_epoch : un timestamp in secondi. Viene aggiornato dal processo di rilascio
delle risorse quando i flag stack_done e module_release_data_called diventano uguali a
1. Successivamente quando il timestamp è “vecchio” (di 20 sec) la struttura
corrente viene rimossa dalla lista e la relativa memoria rilasciata
• sk : la struct sock alla quale una sessione di registrazione è associata. Alla fine di
una sessione tramite questo riferimento la connessione viene resa disponibile a
future sessioni
• private_data : è un riferimento ad una struttura per un utilizzo futuro. Attualmente
viene utilizzata per tenere un riferimento ad una struttura col quale si segnala al
contesto utente la presenza di buffer pieno
• zsynacks_sent : è un valore reso disponibile ad un eventuale sessione di registrazione.
Esso contiene il numero di pacchetti SYNACK inviati ad un endpoint remoto in
risposta ad un pacchetto SYN in ingresso
• zsyns_sent : è un valore reso disponibile ad un eventuale sessione di registrazione.
Esso contiene il numero di pacchetti SYN inviati per stabilire una connessione con
un endpoint remoto
76
struct zsample_sock_sniff_session_wrapper
{
int stack_done;
long secs_from_epoch;
struct zsample_sniff_session *rttKernel;
};
Tale struttura inserita come referenza a quella sock, fa da ponte tra lo stack TCP ed il
modulo kernel delle sessioni di registrazione.
• stack_done : un flag inizialmente a 0 il cui valore viene cambiato a 1 dallo stack
quando la connessione TCP viene chiusa. Da quel momento la struttura
appartenente non sarà più referenziata dallo stack TCP
• secs_from_epoch : un timestamp in secondi. Viene aggiornato dal processo di rilascio
delle risorse quando i flag stack_done diventa uguali a 1. Successivamente quando
il timestamp è “vecchio” (di 20 sec) la struttura corrente viene rimossa dalla lista e
la relativa memoria rilasciata
• rttKernel : la struttura tramite la quale viene implementata la logica di una sessione
di registrazione. Tramite tale referenza lo stack TCP accede alle funzionalità del
modulo kernel
Le seguenti due strutture dati sono state progettate come nodi di una lista ad accesso
sequenziale. Contengono dei dati di payload/utili ed un riferimento al prossimo nodo nella
lista. La creazione di tali liste rende disponibili le referenze ai dati le cui risorse andranno
rilasciate.
struct zsample_sock_sniff_session_wrapper_node_list
{
struct zsample_sock_sniff_session_wrapper *data;
struct zsample_sock_sniff_session_wrapper_node_list *next;
};
Struttura dati contenitrice, progettata per essere un nodo di una lista sequenziale.
77
• data : struttura dati associata a quella sock. Tale referenza è utile nella fase di
rilascio delle risorse
• next : il prossimo elemento nella lista
struct zsample_sniff_session_node_list
{
struct zsample_sniff_session *data;
struct zsample_sock_sniff_session_wrapper_node_list *node_father;
struct zsample_sniff_session_node_list *next;
};
Struttura dati contenitrice, progettata per essere un nodo di una lista sequenziale
• data : struttura dati rappresentante una sessione di registrazione. Tale referenza è
utile nella fase di rilascio delle risorse
• node_father : struttura dati rappresentante la connessione TCP. In questo modo è
possibile risalire alle strutture delle sessioni di registrazione, che verranno rimosse
una volta che una connessione TCP viene chiusa. Tale referenza è utile nella fase di
rilascio delle risorse
• next : il prossimo elemento nella lista
Le seguenti strutture sono utilizzate per implementare la logica delle formule rto. struct tcp_rto_formula_ops { struct list_head list; unsigned long flags; char name[TCP_RTO_FORMULA_NAME_MAX]; struct module *owner; void (*init)(struct sock *sk); void (*release)(struct sock *sk); void (*tcp_set_rto)(struct sock *sk, int origin, void *ptr); void (*tcp_set_rtt)(struct sock *sk, u32 rtt); unsigned long (*tcp_calc_synack_rto)(const struct request_sock *req); };
• list_head : un riferimento al primo elemento della lista a cui appartiene
• flags : campo utile all’implementazione del modulo kernel
• name : nome col quale il modulo kernel viene identificato
78
• owner : un riferimento al modulo al quale la struttura corrente è associata
• init : puntatore a funzione nel modulo kernel che va chiamato una volta solamente e
prima di qualsiasi altra, quando una connessione tcp utilizza la formula corrente.
Tipicamente il suo utilizzo concerne inizializzazioni riguardanti la connessione
TCP.
• release : puntatore a funzione nel modulo kernel che va chiamato una volta
solamente ed alla fine, quando una connessione TCP non utilizza più la formula
corrente. Tipicamente il suo utilizzo concerne de-inizializzazioni riguardanti la
connessione. Speculare al puntatore a funzione precedente.
• tcp_set_rto : puntatore a funzione nel modulo kernel col quale viene aggiornato il
valore RTO.
• tcp_set_rtt : puntatore a funzione nel modulo kernel col quale viene aggiornato il
valore RTT. Il suo motivo non è solamente per l’aggiornamento di RTT, ma anche
per il fatto di rendere tale valore disponibile al modulo kernel
• tcp_calc_synack_rto : puntatore a funzione nel modulo kernel col quale viene
calcolato il valore di RTO durante la fase 3WHS
La struttura seguente fa da ponte tra la struttura precedentemente descritta e la struttura
sock. Esse sono definite in net/sock.h.
struct tcp_rto_formula_specific
{
const struct tcp_rto_formula_ops *ops;
__u32 rto_formula_rto_max;
__u32 rto_formula_rto_min;
__u32 rto_formula_rto_initial;
__u32 rto_formula_rto_three_whs;
void *data;
};
• ops : la struttura rappresentante il modulo kernel che implementa la logica della
formula rto
• rto_formula_rto_max : indica il valore massimo che RTO può avere
• rto_formula_rto_min : indica il valore minimo che RTO può avere
79
• rto_formula_rto_initial : indica il valore iniziale che RTO ha, appena la connessione
tcp viene istituita
• rto_formula_rto_three_3whs : indica il valore che RTO ha inizialmente nella fase
3WHS
• data : tale campo è stato pensato per un utilizzo futuro. Consente alla connessione
di avere una propria struttura dati in relazione col modulo kernel
B.3 Strutture esistenti modificate
Le strutture nuove poc’anzi descritte sono associate a quelle già esistenti. La seguente
struttura viene utilizzata dal sistema nella fase 3WHS. Una volta che la connessione viene
stabilita essa viene rimpiazzata dalla struttura sock. Definita in include/net/request_sock.h.
struct request_sock
{
...
u32 zsynacks_sent;
unsigned long calced_rto;
};
• zsynacks_sent : contatore, tiene traccia degli SYNACK inviati durante la fase di
3WHS
• calced_rto : contiene l’ultimo valore aggiornato di RTO durante la fase 3WHS
Le seguenti modifiche riguardano la struttura sock. Tramite tali campi lo stack tcp
raggiunge sia il modulo kernel della formula rto che quello delle sessioni di registrazione.
Definita in include/net/sock.h
struct sock
{
…
struct zsample_sock_sniff_session_wrapper *zrtt_private;
u32 meas_rtt;
atomic_t tcp_deallocing;
atomic_t sniff_available;
80
u32 zsynacks_sent;
u32 zsyns_sent;
struct tcp_rto_formula_specific rto_formula;
};
• zsample_sock_sniff_session_wrapper : la struttura tramite la quale lo stack TCP
raggiunge il modulo kernel che si occupa delle sessioni di registrazione
• meas_rtt : viene memorizzato l’ultimo valore ‘grezzo’ di RTT
• tcp_deallocing : viene posta a 1 quando la struttura sock viene rilasciata. In questo
modo viene informata la parte che si occupa delle sessioni di registrazione che il
riferimento alla struttura sock associata ormai è NULL
• sniff_available : viene posta a 1 quando una sessione di registrazione termina. In
questo modo la relativa connessione TCP è disponibile ad ulteriori sessioni
• zsynacks_sent : contatore, tiene traccia del numero di pacchetti SYNACK inviati
durante la fase 3WHS
• zsyns_sent : contatore, tiene traccia del numero di pacchetti SYN inviati durante la
fase 3WHS
• rto_formula : la struttura tramite la quale lo stack TCP raggiunge il modulo kernel
per l’aggiornamento dinamico di RTO
B.4 Codice ex novo
net/ipv4/rtt_sampling.c
Viene implementata la logica relativa alle sessioni di registrazione. Riguarda sia le
funzioni con le quali esso si interfaccia col modulo kernel per l’inizio e termine delle
sessioni di registrazione, che quelle con le quali si interfaccia con lo stack TCP. Inoltre vi
si trovano tutte le funzioni riguardanti il rilascio delle risorse occupate per le sessioni di
registrazione. Per ulteriori dettagli fare riferimento al codice sorgente stesso.
net/ipv4/tcp_rto_formula.c
Viene implementata la logica relativa alle formule per l’aggiornamento dinamico di RTO.
Una parte delle funzioni implementate, riguarda l’interfaccia con il contesto utente: come
aggiungere e rimuovere una formula oppure fornire la lista di quelle disponibili nel
81
sistema. Dall’altra parte ci sono le funzioni riguardanti l’interfaccia con lo stack TCP. Ci si
riferisce alle funzioni con le quali una connessione viene associata/deassociata con/da una
formula rto. Infine viene fornita una formula per il calcolo di RTO che verrà utilizzata da
connessioni TCP finchè non si disporrà diversamente: associare la formula di default
oppure una a scelta. Tale formula implementa quella attualmente utilizzata nel kernel. Il
suo motivo è semplicemente quello di avere il sistema sempre in una situazione stabile.
net/ipv4/tcp_rto_casa.c
E’ la formula rto disponibile nel sistema già dall’inizio. Essa inizialmente è l’unica
formula disponibile, quindi quella di default. Implementa il calcolo di RTO come
attualmente nel kernel viene fatto. Il modulo kernel col quale tale logica è implementata
non è rimovibile, affinche il sistema abbia sempre una formula rto disponibile.
B.5 Codice esistente modificato
In molti punti nel codice del kernel sono state apportati delle modifiche. Le righe di codice
nuove aggiunte verranno precedute da ‘/*NEW*/’, invece quelle commentate da
‘/*OBSOLETE*/’. Per ognuno dei file sorgente modificati seguono una descrizione dei
punti più importanti.
net/ipv4/inet_connection_sock.c
• inet_csk_reqsk_queue_prune : il corso d’esecuzione dello stack tcp viene deviato per il
modulo kernel che implementa la formula rto (vedasi tcp_synack_calc_rto)
net/ipv4/sysctl_net_ipv4.c
Viene reso possibile tramite l’interfaccia /proc/sysctl la gestione delle formule rto:
inserimento/rimozione e lista delle formule disponibili.
82
net/ipv4/tcp.c
Viene reso possibile tramite l’interfaccia get/setsockopt l’associazione di una formula rto a
scelta tra quelle disponibili alla connessione TCP corrente.
net/ipv4/tcp_minisocks.c
• tcp_create_openreq_child : tale funzione viene chiamata quando una connessione
incoming viene stabilita. Dalla struttura request_sock viene costruita una sock,
copiando anche il numero di pacchetti SYNACK inviati e l’ultimo valore
aggiornato di RTO durante la fase 3WHS.
net/ipv4/tcp_input.c
• tcp_init_metrics : tale funzione viene chiamata appena una connessione TCP viene
stabilita. Il corso d’esecuzione dello stack viene deviato nel modulo kernel che
implementa la formula rto. Inoltre nel caso una sessione di registrazione fosse
attiva viene inoltre fatta una chiamata al rispettivo modulo.
• tcp_valid_rtt_meas : tale funzione viene chiamata ogni volta che un ACK di
pacchetto/i viene elaborato. Il corso d’esecuzione dello stack viene deviato nel
modulo kernel che implementa la formula rto. Inoltre nel caso una sessione di
registrazione fosse attiva viene inoltre fatta una chiamata al rispettivo modulo.
net/ipv4/tcp_ipv4.c
• tcp_v4_err : tale funzione viene chiamata quando il modulo icmp rileva un errore es.
HOST_UNREACHABLE. Il corso d’esecuzione dello stack viene deviato nel
modulo kernel che implementa la formula rto. Inoltre nel caso una sessione di
registrazione fosse attiva viene inoltre fatta una chiamata al rispettivo modulo.
• tcp_v4_send_synack : tale funzione viene chiamata ogni volta che un pacchetto
SYNACK viene inviato. La modifica riguarda l’aggiornamento del contatore di
SYNACK inviati.
83
• tcp_v4_syn_recv_sock : tale funzione viene chiamata appena una connessione TCP
incoming viene stabilita. La connessione TCP appena creata, eredita la formula rto
del padre ovvero della connessione TCP in accept dalla quale proviene.
• tcp_v4_init_sock : tale funzione viene chiamata quando una struttura sock viene
creata. Oltre ad associare alla struttura la formula rto di default disponibile, essa
inizializza una serie di variabili.
• tcp_v4_destroy_sock : tale funzione viene chiamata quando una struttura sock viene
rilasciata. L’implementazione riguarda l’aggiornamento di variabili utili per il
rilascio delle risorse di eventuali sessioni di registrazione. Inoltre il riferimento al
modulo della formula rto viene rimosso.
net/ipv4/tcp_timer.c
• tcp_retransmit_timer : tale funzione viene chiamata quando il timer RTO scade. Il
corso d’esecuzione dello stack viene deviato nel modulo kernel che implementa la
formula rto. Inoltre nel caso una sessione di registrazione fosse attiva viene inoltre
fatta una chiamata al rispettivo modulo.
net/ipv4/Kconfig
le modifiche riguardano la configurazione fatta per la compilazione del kernel. In sostanza
riguardano la scelta della formula rto da compilare integrata nel kernel.
net/ipv4/Makefile
le modifiche riguardano i vari object header files da includere nella fase di compilazione.
In particolare la componente che implementa le sessioni di registrazione e la gestione delle
formule rto.
rc.modules-2.6.33
le modifiche riguardano l’esecuzione automatica nella fase di boot del sistema. In
particolare la creazione dei device per le sessioni di registrazione oppure varie formule rto
sperimentali.
84
C. Moduli kernel
I moduli kernel creati riguardano:
• formula per l’aggiornamento dinamico di RTO
• sessione di registrazione
C.1 Modulo formula rto
Il modulo implementa le api tipiche register e unregister le quali vengono chiamate al
caricamento ed alla rimozione del modulo stesso. Seguono le api con le quali il modulo
stesso viene associato alla connessione tcp: xxx_init e xxx_release. Infine le api utilizzate
dallo stack tcp per aggiornare RTO: xxx_set_rto, xxx_set_rtt, xxx_tcp_calc_synack_rto. E’
proprio in questo modulo che viene implementata la funzione che aggiorna RTO in
funzione delle condizioni per cui si verifica:
• ack ricevuto
• rto scaduto
• connessione appena stabilita
• errore modulo icmp
Il contenuto (file sorgente + Makefile) di questo modulo si trovano nella subdirectory:
tesi/chu per la formula rto ‘chu’ e tesi/speedy per la formula rto ‘speedy’.
C.2 Modulo sessione di registrazione
Il modulo implementa le api tipiche xxx_init e xxx_exit le quali vengono chiamate al
caricamento ed alla rimozione del modulo stesso. Seguono le api per la gestione del
device: apertura e chiusura ed infine le chiamate ioctl. Queste ultime in base ai parametri si
distinguono in:
85
• inizio sessione
• attesa di dati in arrivo
• lettura della formula rto associata alla connessione TCP
• associazione di una formula rto a scelta tra quelle disponibili alla connessione TCP
• fine sessione
L’apertura e la chiusura del device coincide con la creazione e la rimozione di una zona di
memoria per il memory mapping. Infine in questo modulo viene implementata anche la
funzione che si occupa di immagazzinare opportunamente i valori RTT e RTO nelle
relative strutture dati, quindi informare il contesto utente in presenza di.
Il contenuto (file sorgente + Makefile) di questo modulo si trovano nella subdirectory:
tesi/rtto.
D. Contesto utente: skeleton, client, server
Nel contesto utente è stato implementato un layer per le sessioni di registrazione al fine di
semplificarne l’utilizzo. Utilizzando questo layer sono stati implementati anche gli altri
due programmi di test: client e server.
D.1 Skeleton
Lo skeleton oltre a nascondere i dettagli riguardanti l’apertura/chiusura del device e
inizio/fine della sessione si occupa anche di prelevare i dati dal contesto kernel per poi
consegnarli a quello utente. Quest’ultima operazione è resa possibile tramite un puntatore
di funzione col quale lo skeleton invia i dati all’applicativo. Segue il necessario per iniziare
una sessione di registrazione.
Il contenuto (file sorgente + Makefile) di questo modulo si trovano nella subdirectory:
tesi/xskeleton.
86
/*****************************************************************************************/
rtt_ctrl* driver_ctrl;
static void wrapper_take_data_pointer(void *ptr, struct zsample samples[], int len)
{
// elaborazione dei dati
}
main
{
…
// apertura device
driver_ctrl.state = 0;
driver_ctrl.take_data_cplus = wrapper_take_data_pointer;
driver_ctrl.driver_name = ”/dev/rtto0”;
open_device(&driver_ctrl, &err_code);
// inizio sessione
driver_ctrl.conn.saddr = inet_addr(“192.168.1.101”);
driver_ctrl.conn.daddr = inet_addr(“85.11.172.64”);
driver_ctrl.conn.sport = 54708;
driver_ctrl.conn.dport = 80;
begin_session(&driver_ctrl, &err_code);
// loop continuo
while(1) sleep(1);
}
/*****************************************************************************************/
D.2 Client
L’applicativo client si collega alla porta 80 di un indirizzo ip (oppure web previa
risoluzione dns), quindi effettua il file upload. Nel caso specifico il sito web sul quale è
stato testato è “upload.factory.com”: un sito web che offre gratis la possibilità di file
87
upload/download. Ovviamente un altro sito web che offre le stesse funzionalità può
richiedere delle modifiche nel modo in cui la richiesta http viene fatta. Inoltre esso inizia
una sessione di registrazione per ogni file upload. Con i parametri di comando passati in
ingresso è possibile selezionare l’indirizzo di destinazione, il device da utilizzare per le
sessioni, la formula rto da utilizzare ed infine il nome file per l’upload.
Il contenuto (file sorgente + Makefile) di questo modulo si trovano nella subdirectory:
tesi/xuploader.
D.3 Server
L’applicativo server offre le stesse funzionalità di quello client. Tra i parametri passati in
ingresso l’indirizzo ip destinatario viene sostituito dalla porta TCP sulla quale il server
starà in ascolto.
Il contenuto (file sorgente + Makefile) di questo modulo si trovano nella subdirectory:
tesi/xserver.