<< Torna agli Approfondimenti Tematici
|
|
Premessa
Il TCP è il protocollo di livello 4 dello stack TCP/IP. É stato sviluppato per implementare le principali funzionalità del livello trasporto includendo session multiplexing, affidabilità e controllo di flusso.
Figura 1
In Figura 1 è rappresentata l’intestazione di un segmento TCP. I campi mediante i quali viene gestita la funzionalità di session multiplexing sono i primi due: source e destination port. In merito all’affidabilità, questa viene controllata dai due campi successivi: sequence number e acknowledgement number. In questo articolo porremo la nostra attenzione alla terza di queste funzionalità: il controllo di flusso.
Problematica
Come sappiamo il TCP è un trasporto di tipo connection oriented; entrambi i dispositivi tra cui è attiva una sessione tengono traccia di tutti i dati trasmessi, in modo che la perdita di uno o più segmenti, il fatto che questi arrivino fuori sequenza, rende possibile la ritrasmissione di quelli persi e il riordino di quelli ricevuti in ordine non corretto.
Nell’ottica di gestire il fatto che il buffering temporaneo dei dati (ove essi risiedono temporaneamente fino a che la corretta applicazione possa processarli) sia limitato, i dispositivi concordano il quantitativo di dati che possano essere trasmessi prima che sia necessario un acknowledge. Questo valore è conosciuto come “window size” e viene comunicato, e gestito, mediante il campo window size dell’intestazione TCP (16 bits).
Per attivare una sessione TCP tra due dispositivi si passa attraverso un processo noto come “three way handshake”.
Figura 2
In Figura 2 è visualmente descritto tale processo.
Il dispositivo A deve scambiare dati con il dispositivo B mediante un’applicazione che usa come trasporto TCP. Il primo segmento (SYN) ha come compito pricipale quello di segnalare al proprio interlocutore quello che sarà il sequence number iniziale (se catturato con Whireshark il primo sequence viene visualizzato come 0 ma in realtà si tratta di un numero random; per visualizzare il vero valore è necessario modificare una opzione dell’applicativo stesso). Viene chiamato così in quanto il flag SYN viene impostato al valore 1 (mentre quello ACK a 0 in quanto, essendo il primo, l’apparato che inizia la connessione non può sapere quale sarà il numero iniziale scelto dalla controparte).
B risponde con un segmento noto come SYN,ACK che serve a completare la fase di sincronizzazione dei due dispositivi. In questo caso entrabi i flags SYN e ACK sono impostati a 1.
A questo punto la sessione è attiva (established) e A può confermare l’avvenuta ricezione del segmento; poichè i dispositivi sono sincronizzati il flag SYN viene impostato a 0.
Un’altro parametro che viene negoziato in questa fase è appunto il window size. Nell’esempio ho ipotizzato che i due proponessero il valore 32768 (metà del valore massimo ) indicando reciprocamente la possibilità di allocare 32K di buffer per il traffico ricevuto. Questo valore cambierà dinamicante durante la connessione in funzione delle condizioni dei due (da qui l’espressione “sliding windows”).
A questo punto A deve inviare traffico a B. In base all’informazione ricevuta da B in fase iniziale, A può trasmettere 32K di dati (in intervalli grandi quanto il maximum segment size o MSS) prima di fermarsi in attesa di ricevere la conferma di ricezione (ACK) da parte di B. Supponendo che il MSS abbia valore 1460, A può trasmettere 22 segmenti prima di riempire il buffer di ricezione di B.
Quando B invia la conferma dell’avvenuta ricezione può, se necessario, modificare il proprio windows size. Immaginando che l’applicazione sul dispositivo B sia riuscita a processare solo metà dei dati (in quanto la CPU di B è particolarmente occupata da altri processi ad esempio), B può abbassare il proprio windows size a 16K. Se invece non fosse riuscito del tutto a processare la finestra di dati potrebbe indicare un window size di 0 segnalando di non avere più spazio per memorizzare ulteriori dati.
Nel momento in cui il protocollo TCP è stato sviluppato questa modalità di funzionamento si è rilevata particolarmente efficiente. Daltronde la velocità dei links in quel periodo non era particolarmente performante.
Oggi la situazione è significativamente diversa: in ambito locale (LAN) la banda disponibile varia tra 10Mbps e 100Gbps (tipicamente a disposizione dell’utente finale ci sono 100Mbps mentre la più diffusa in ambito Data Centre è 10 Gbps). E per quanto riguarda il ritardo (delay), esso rimane contenuto nell’ ordine di milli/microsecondi.
La limitazione del numero di segmenti che possono essere inviati in attesa dell’ACK, dovuta al window size, incide significativamente sulle prestazioni delle applicazioni che usano TCP, nonostante a disposizione del client ci siano 100 Mbps.
Se poi ci riferiamo a connessioni con ampia banda e delay significativo (ad esempio connessioni satellitari) una particolare situazione potrebbe verificarsi: è possibile che il sender riempia il buffer del receiver prima di ricevere da esso un acknowledege.
Provo a fare un esempio semplice: viene stabilita una connessione TCP tra due apparati collegati mediante un link LAN a 10 Mbps con un delay (unidirezionale) di 80 ms. Entrambi impostano il window size al valore massimo di 64K. Il potenziale volume di dati che i due possono scambiare unidirezionalmente in base alla formula Bandwith*Delay (o BDP Badwith Delay Product) sarebbe: 10.000.000 bps diviso 8 bits per byte,moltiplicato per 0.08 secondi equivale a 100.000 bytes.
In altri termini, se A trasmettesse di continuo, invierebbe 100K prima che B ricevesse il primo byte! Ma poichè B utilizza 64K come window size, A può trasmettere solo 64K prima di fermarsi ed aspettare l’acknowledge di B. Ovviamente per non complicare eccessivamente l’esempio non ho tenuto conto dell’overhead causato dal TCP stesso e dai protocolli sottostanti.
La conseguenza principale, che già risulta evidente quando il link è a 10Mbps e che diventa ovviamente più significativa quando la banda aumenta (queso tipo di links vengono talvolta denominate Large Fat Networks), è che il troughput che questo tipo di connessioni potrebbero offrire non viene sfruttato del tutto.
Soluzione
Per risolvere il problema la soluzione che si è trovata viene denominata Window Scaling.
Il window scaling venne introdotto nell’ RFC 1072 e poi ridefinito nel RFC 1323. La logica che pilota il window scaling consiste nell’ ampliare il window size da 16 a 32 bits.
Messa in quesi termini la soluzione sembra troppo semplice ed infatti non lo è. Non era, e non è, possibile semplicemente modificare l’intestazione del protocollo TCP allocando 32 bits invece di 16 nel campo window size: renderebbe la “nuova” e la “classica” implementazione del TCP incompatibili e vista la mole di installato l’ipotesi risulta impraticabile.
Per risolvere il problema si è pensato di sfruttare il concetto di TCP options.
Sfruttando il concetto di options è possibile aggiungere funzionalità al protocollo TCP lasciando intatto l’header originale.
Nello specifico l’opzione window scaling istruisce i dispositivi in merito all’interpretazione da dare al valore indicato nel campo window size. Se considerarlo al valore indicato dallo stesso o se fare un’operazione di “spostamento di bits” (bitwhise shifting) e di quanti, incrementandolo quindi in accordo con la scala delle potenze del 2 ottenendo quindi valori significativamente superiori.
Se nell’opzione è indicato il valore 1, si inidica di spostare verso sinistra di uno il valore indicato di conseguenza raddoppiandolo. Due invece indica di spostare il valore di due bits verso sinistra quadrupicandolo di conseguenza. Di conseguenza, spostando il bit di riferimento di 7 (ad esempio) rispetto al valore indicato nel window size, lo stesso risulterebbe moltiplicato di 128.
Figura 3
La Figura 3 ci da un esempio visivo di quello che comporta la presenza di tale opzione quando il valore impostato è per l’appunto 7.
Importante sottolineare che l’opzione window scaling viene impostata solo una volta durante la fase di setup della connessione (SYN) e deve essere impostata da entrambi i dispositivi per poter essere utilizzata. Inoltre il valore massimo impostabile è 14. Infine, mentre il valore del windows size cambia dinamicamente, quello dello scaling rimane quello negoziato in fase di setup della connessione TCP.
Prima di concludere aggiungiamo una ulteriore considerazione: chi deve impostare tale opzione?
I sistemi operativi Microsoft implementano il window scaling da Windows 2000 ma è possibile disabilitarlo. Per quanto riguarda gli Unix, l’implementazione varia in funzione delle implementazioni e delle releases.
Una ulteriore possibilità di sfruttare il window scaling (e non solo ovviamente) consiste nell’aggiungere all’infrastruttura oggetti che possano ottimizzare le sessioni TCP (tipo acceleratori) che i dispositivi finali gestiscono in modo classico o non ottimale.