User Tools

Site Tools


content:networking:wireshark_banda

Analizzare problemi di banda con Wireshark

Intro

In questo articolo analizzeremo il download di un file corposo tramite Wireshark; sarà un'occasione per affrontare alcuni aspetti della comunicazione TCP tra cui:

  • SEQ e ACK numbers
  • Selective Acknowledgement (SACK)
  • Duplicate ACKs (Dup ACK)
  • TCP Retransmission e Fast Retransmission
  • Initial Round Trip Time (iRTT)
  • Outstanding bytes (o bytes in flight)
  • Bandwidth Delay Product (BDP)
  • … e altro ancora

La connessione inizia facendo un download dell'ISO della nuova release di debian da https://www.debian.org/distrib/, scegliendo la small installation a 64-bit.

Si tratta di 334 MB di file; dal browser si vede come il download parte relativamente veloce, a 10 MB/s, per poi diminuire progressivamente, fino a stabilizzarsi a 7.4 MB/s.

Analisi del traffico

Conversations

Come prima cosa conviene filtrare la conversazione di rete pertinente. E' sufficiente quindi andare in Statistics - Conversations, selezionare la tab IPv4 e ordinare per Bytes decrescenti; la prima riga è quella che ci interessa (la differenza rispetto alle dimensioni del file scaricato è dovuta agli header):

Filtriamo quindi su di essa con tasto dx e Apply as a filter - Selected - A↔B e poi chiudiamo la finestra; sulla finestra principale di Wireshark compariranno solo i pacchetti appena filtrati.

Verificare il Throughput

Capture file properties

Per avere un'idea precisa del throughput rilevato si può andare anche in Statistics - Capture file properties; poi sotto Statistics ci sono i valori in MB/s o Mb/s (guardare sotto la colonna 'Displayed'). Il valore restituito è la media.

La stessa funzione si può richiamare premendo il secondo pulsante in basso a sinistra:

Throughput

Esiste anche un menu opportunamente chiamato Throughput, sotto Statistics - TCP Stream Graphs - Throughput:

Qui si vede l'andamento del throughput nel tempo, con l'evidenza di alcuni rallentamenti all'inizio.

Grafico con tcptrace

Poi conviene farsi un'idea visiva della comunicazione e andare quindi in Statistics - TCP Stream Graphs - Time Sequence (tcptrace) (questo tool è stato introdotto qui):

Un grafico di un download deve avere la rappresentazione di una retta inclinata che avanza uniformemente, come quella sopra: in teoria, maggiore il gradiente, maggiore la banda. Se ci fossero degli appiattimenti (non è il caso sopra) saremmo in presenza di ritardi nel trasferimento dei dati, fenomeno da indagare

Si può vedere come il download dura circa 46 s; dividendo le dimensioni del file per questa durata si ottiene:

334 MB / 46 s = 7.2 MB/s

che corrisponde grossomodo alla banda segnalata dal browser durante il download. Inoltre nella curva si notano alcuni glitch in corrispondenza dei secondi 4, 9, 24, 30 e 38.

Effettuando quindi uno zoom su alcune zone del grafico si possono estrapolare le seguenti informazioni.

Slow Start

All'inizio si nota quello che viene definito come slow start

Una spiegazione di questo comportamento iniziale, perfettamente normale ed in linea con gli RFC, si può trovare qui. Fino ad adesso tutto ok.

Delayed ACK

E' evidente poi un pattern; il server invia spesso due pacchetti (soprattutto da 1440 o 2880 bytes) e il client ne fa l'ACK.

Per capire perchè sono presenti pacchetti da 2880 byte vedi TSO/LRO

Anche questo comportamento è standard durante questo tipo di comunicazione (download):

[//Due segmenti da 1440 inviati dal server, un ACK per entrambi dal client//]

Quanto sopra è l'implementazione dell'RFC 1122, che definisce il Delayed ACK; in questo RFC si parte dal presupposto che, se un host riceve dei dati, non è efficiente nè per esso nè per la rete in generale se invia un ACK ad ogni segmento ricevuto, per l'overhead che ne deriva. Quindi il receiver:
  • invierà un ACK solo dopo aver ricevuto due interi segmenti MSS
  • comunque non aspetterà più di un intervallo solitamente a 100 ms o 500 ms, prima di essere obbligato ad inviare un ACK, anche se in presenza di un solo segmento ricevuto

Nel trace ci sono degli ACK anche dopo un solo segmento ricevuto, ma questo è di dimensione 2880 oppure 4320 byte, quindi in effetti si tratta già di due MSS.

Glitch

Ingrandendo il grafico in corrispondenza dei glitch evidenziati prima si vede quanto segue:

Sembrano non promettere nulla di buono…

'TCP Previous segment non captured'

Infatti, dopo circa 3,5 secondi si nota questo comportamento diverso e qui è dove cominciano i problemi. Dal server riceviamo il pacchetto 44841, che però segnala 'TCP Previous segment non captured'; infatti nel grafico si nota un gap:

[//Un segmento non ricevuto ("captured") sotto la barra blu verticale e le barre rosse verticali in corrispondenza dei Dup ACK del client//]

'TCP Dup ACK'

Il client segnala la cosa nel pacchetto 44842 facendo l'ACK dell'ultimo pacchetto correttamente ricevuto, quello con finale '3603'. Il pacchetto viene marchiato da Wireshark come 'TCP Dup ACK'. Inoltre, andando nei packet details, nelle Options del TCP compare un SACK block del client:

[//SACK option del client//]

Nel grafico del tcptrace i Dup ACK sono le tacchette sulla riga gialla; mentre il SACK block è rappresentato dalle barrette rosse.

In una battuta, con il pacchetto 44842 il client sta segnalando quanto segue:

“Hey server, ho ricevuto un pacchetto da te, ma quello di prima mi manca. Ti faccio quindi nuovamente l'acknowledge dell'ultimo correttamente ricevuto (il '3603'), così che tu possa spedirmi il pacchetto mancante. In più l'ultimo pacchetto lo tengo nel mio receiver buffer, affinchè tu non debba rispedirmelo. Solo una volta che mi manderai il pacchetto mancante ti farò l'acknowledge anche di quest'ultimo”. Tu, per favore, registra questi SACKed blocks nel tuo sender buffer, così non sarai obbligato a rispedirmeli.

Da come è stato detto, si può capire che il receiver salva i pacchetti oltre il confine dell'acknowledgement, che il sender gli invia, in un buffer, pronti per essere spediti appena gli arriva il pacchetto intermedio mancante:

[//Il TCP ragiona secondo un meccanismo **cumulativo**//]

Dall'immagine sopra si può constatare come il receiver non possa effettuare un ACK dei new data, fino a che il sender non ha inviato la parte in grigio che, per qualche motivo, il receiver non ha ricevuto. Ma il receiver memorizza ugualmente i new data nel suo buffer, pronto per effettuarne l'ACK una volta che il sender gli abbia ritrasmesso il pacchetto mancante.

Il server non invia ancora il pacchetto '3603', ma invece continua ad inviare successivi pacchetti. Il client non può fare altro che segnalargli nuovamente un 'Dup ACK' e ingrandire il SACK block per accomodare il nuovo pacchetto (con uno shift verso destra del right edge del SACK):

Siccome il server continua a non inviare il pacchetto '3603', mentre ne invia altri, il client non può far altro che continuare ad ingrandire il SACK block, fino a che succede che manca un altro pacchetto dal server, segnalato in Wireshark da un nuovo 'TCP Previous segment non captured', così rappresentato nel grafico (notare il nuovo gap):

[//Un nuovo segmento inviato dal server e marcato come gap//]

Il client accomoda il nuovo segmento ricevuto, successivo a quello perso, nel suo buffer. Non sposta il right edge del SACK block, ma ne crea un altro. Il SACK cambia quindi così:

[//Adesso i buffer SACK sono due//]

Poi ci sarà un nuovo segmento perso e il client sarà costretto a far posto al successivo così. I SACK block diventano tre:

L'RFC stabilisce che il server debba reinviare il pacchetto segnalato dopo quattro Dup Ack (meccanismo della Fast Retransmission); perchè non lo fa? La spiegazione è più sotto, ma fondamentalmente dipende dalla latenza tra client e server

Nel caso in cui venisse segnalato un nuovo segmento perso, il SACK block più vecchio ('19905043-19915123') scomparirebbe dalle TCP Options, per fargli posto, ma rimarrebbe nel buffer del receiver. L'immagine sottostante mostra i segmenti verticali rossi che corrispondono ai SACK block, mentre un pacchetto perso corrisponde ad un vuoto tra i segmenti. I SACK block più vecchi (cioè quelli più in basso) scompaiono per far posto a quelli più nuovi:

[//I segmenti verticali rossi corrispondono ai SACK block, gli spazi vuoti tra i segmenti a pacchetti persi//]

I SACK block (segmenti verticali rossi) di cui si fa l'advertisement possono essere al massimo 3 in un dato istante. Ma il client e il server terranno nota di questi, dei precedenti e dei successivi nei loro, rispettivamente, receiver e sender buffer

Una conseguenza dei pacchetti persi sono i cosiddetti packets in-flight, cioè pacchetti non ancora acknowledgeati; questi aumenteranno in corrispondenza di Dup ACK per poi azzerarsi una volta che il receiver riesce a ricevere dal sender pacchetti che non ha ricevuto e a fare ACK dei byte che ha nel suo buffer.

'TCP Fast Retransmission'

Adesso che abbiamo capito come funziona il Selective Acknowledgement, c'è da capire perchè il server non si attivi dopo aver ricevuto quattro messaggi di Dup Ack uguali, effettuando delle TCP Fast Retransmission dei byte che mancano al client. Se settiamo un time reference sul quarto pacchetto di Dup ACK (44841) e verifichiamo il tempo trascorso fino a quando (47047) il server non effettua la prima Fast Retransmission del famoso pacchetto '3603', possiamo constatare che sono passati circa 205 ms (colonna 'Time'):

Il client non fa l'acknowledge di '19905043', ma di '19915123'; come si è visto prima, il blocco SACK '19905043-19915123' è stato presente solo temporaneamente nelle TCP Options, ma è stato comunque salvato nel buffer del client. Quindi quest'ultimo, una volta che il server ha spedito il pacchetto mancante, è riuscito a fare l'acknowledge di tutti i byte fino a '19915123'.

Quanto sopra fa capire una volta di più come il TCP ragioni in ottica di acknowledgement cumulativi

Vediamo adesso di capire perchè il server abbia risposto con apparente ritardo.

Ispezionando la 3-way handshake, si nota come il server reagisca alla SYN del client inviando un SYN-ACK in 222 ms; questo valore corrisponde al RTT (Round Trip Time), che è congruo, considerato che il server si trova in Svezia. Quindi, in generale, il server non potrà mai rispondere alle richieste del client prima di circa 200 ms; si capisce allora come il server abbia ricevuto il quarto Dup ACK dal client solo dopo 100 ms (metà RTT) e abbia potuto inviare la Fast Retransmission dopo altri 100 ms, e non prima. Alla base c'è quindi un problema di latenza.

Bandwidth Delay Product (BDP)

Il Bandwidth Delay Product (BDP) è un valore della rete dato da:

Banda x Latenza = BDP

In questo caso, assumendo che il server abbia una banda superiore, il limite è dato dalla banda del client, che è pari a 62Mbps.

Calcoliamo quindi il BDP della rete:

BDP = 62 Mb/s x 0.222 s = 13.764 Mb = 1.72 MB = 1800000 bytes (circa)

Il BDP corrisponde alla massima quantità di dati possibile sulla rete in ogni momento e dovrebbe essere minore o uguale al valore della TCP Windows size del receiver

Dal trace si nota come la Windows size del receiver all'inizio è piccola per poi aumentare fino a 3145728 byte, quindi sta sfruttando correttamente la capacità della rete data dal BDP.

Window Scaling

La Window size è un valore presente nell'header TCP a 16 bit, che può quindi raggiungere un valore massimo di 65535 byte. Per superare questo limite il client può usare la TCP option Window Scale, che deve essere specificata nel SYN iniziale della connessione. Si tratta di un moltiplicatore da applicare alla Window size. In questo caso il client ha fatto un advertisement iniziale di una Window Scale da 128, quindi il valore effettivo corrisponde alla Calculated Window Size:

Il window scaling viene stabilito durante la 3-way handshake, ma la calculated window size viene usata solo dopo questa fase

E' possibile visualizzare un grafico focalizzato esclusivamente sull'andamento del window scaling andando in Statistics - TCP Stream Graphs - Windows scaling. Come si vede qui di seguito, all'inizio la window size si abbassa fino ad arrivare a zero dopo pochi secondi, per starci fino a quasi 40 secondi:

[//Andamento della receiver window size in verde, mentre i pallini sono i dati inviati. Quando c'è una //zero window condition// non ci sono dati scambiati.//]

Disabilitare SACK (solo per prova)

Per comprendere il valore effettivo del SACK (Selective Acknowledgement) si può provare, per test, a disabilitarlo. Su Linux si fa in questo modo:

sysctl -w net.ipv4.tcp_sack=0

E' un'impostazione volatile, che al successivo riavvio non permane.

Già dal grafico tcptrace si nota un comportamento abnorme; il download ha impiegato 6 volte tanto (240 s) rispetto a prima e si notano avvallamenti, indici di un download a singhiozzi:

//Disabilitando il SACK il download procede a singhiozzi//

Il download dello stesso file, con il SACK disabilitato, ha impiegato 6 volte tanto!

Zoomando si verificano altri dettagli:

//Pacchetti trasmessi dal server, non //acknowledgeati// dal client e ritrasmessi dal server

Nello zoom sopra, si notano i pacchetti spediti dal server a sinistra (verso i 3 secondi) e, dopo un intervallo, gli stessi pacchetti ritrasmessi più a destra (verso i 3,6 secondi), non essendo attivo il meccanismo del SACK.

Il primo pacchetto perso dal client è il 17454, che lo segnala al server come Dup ACK, richiedendone il reinvio. Come spiegato sopra, la richiesta di reinvio (il Dup ACK) avviene segnalando nuovamente l'ACK del precedente pacchetto correttamente ricevuto (Sequence nr. 20321203); ma adesso, con il SACK disabilitato, nelle options il client non tiene più traccia dei pacchetti successivi, anche se continua a salvarli nel suo buffer. Quindi la differenza sembra solo lato server, che, senza SACK, non ha evidenza dei segmenti che il client ha nel suo buffer.

TCP Retransmission

Il server è quindi costretto a rispedire il segmento segnalato dal receiver; risponde dopo circa 100 ms (quando è stata effettuata questa prova di disabilitare il SACK la latenza era migliore rispetto ai test sopra con il SACK attivo) con una TCP Retransmission:

Ciò inizia al segmento 20935, dove il server spedisce gli agognati (dal client) byte 20321203-20322643 (1440 byte). Al segmento 20936 il client, che aveva disperatamente richiesto il pacchetto 20321203, fa l'ACK di 20365843 byte, che corrisponde a quanto aveva nel frattempo memorizzato nel suo buffer. In particolare sembra che nel buffer abbia tenuto i byte fino all'invio da parte del sender del successivo TCP Segment not captured.

Al segmento 20937 il sender fa una nuova TCP retransmission di 20367283-20367283 (1440 byte); il receiver fa l'acknowledge di 20404723, cioè questo segmento, che non aveva ricevuto, più altri che aveva tenuto nel buffer e dei quali non poteva ancora fare l'acknowledgement.

'TCP Spurious Retransmission'

Poi, dal segmento 20939 in poi, ci sono una serie di TCP Spurious Retransmission e TCP Dup ACK. Probabilmente a causa della latenza, anche se il receiver aveva inviato l'acknowledge di 20404723, il sender non se ne avvede ed invia 20367283-20368723 (1440 byte). Si tratta di byte che il receiver aveva già acknowledgeato e per questo vengono segnalati come spurious, nonchè come Dup ACK.

Di questi spurious e relativi Dup ACK ce n'è una sfilza; il client sta segnalando quanto segue:

“Hey server, di questi pacchetti ti ho già effettuato l'acknowledge; me ne serve uno successivo, il 20404723.”

Ma fintantochè queste richieste non arrivano al sender, superando la latenza, questi continuerà nell'invio.

Ad un certo punto, c'è una serie di pacchetti stile botta-risposta; si tratta di comunicazione sincrona, visto la latenza pari al RTT, dove il receiver segnala la mancanza di un sequence number e il sender glielo invia:

[//Il receiver segnala un sequence number, il server lo invia. Notare le latenze//]

Corrisponde a questo tratto del tcptrace (la riga in basso):

Il comportamento qui sopra si ripete per tre volte di fila:

Da notare che il sender invia dei byte tramite le curvette, ma non vengono ricevuti dal receiver, quindi non ne fa l'ACK, e allora il sender è costretto a ritrasmetterli un segmento alla volta, un RTT alla volta, impiegando molto tempo. Infatti:

Questo comportamento dura circa 75 secondi!

C'è poi un tratto, dai 75 ai 100 secondi, in cui il download avviene in maniera abbastanza spedita, con una sequenza di 2 SEQ-1 ACK, per poi ripresentare i problemi sopra segnalati.

Conclusioni

Una lezione che possiamo trarre è quindi che:

In presenza di segnalazioni di TCP Retransmission o TCP Spurious Retransmission verificare l'abilitazione o meno del SACK nel 3-way handshake; in caso non lo sia abilitarlo
content/networking/wireshark_banda.txt · Last modified: 2022/07/08 16:11 by admin