2010-03-30 15 views
10

Ho letto di quello che succede dopo che i pacchetti sono stati catturati dai NIC e più ne leggo, più mi confondo.Cosa succede dopo che un pacchetto è stato catturato?

In primo luogo, ho letto che tradizionalmente, dopo che un pacchetto è stato catturato dalla scheda NIC, viene copiato in un blocco di memoria nello spazio del kernel, quindi nello spazio utente per qualsiasi applicazione che poi funziona sui dati a pacchetto . Poi ho letto di DMA, in cui la NIC copia direttamente il pacchetto in memoria, bypassando la CPU. Quindi la NIC -> memoria del kernel -> flusso di memoria dello spazio dell'utente è ancora valida? Inoltre, la maggior parte della scheda NIC (ad esempio Myricom) utilizza DMA per migliorare i tassi di acquisizione dei pacchetti?

In secondo luogo, l'RSS (Receive Side Scaling) funziona in modo simile in entrambi i sistemi Windows e Linux? Posso solo trovare spiegazioni dettagliate su come funziona il RSS negli articoli MSDN, dove si parla di come RSS (e MSI-X) funziona su Windows Server 2008. Ma lo stesso concetto di RSS e MSI-X dovrebbe ancora applicarsi ai sistemi Linux, giusto ?

Grazie.

saluti, Rayne

+1

Google per la copia in rete zero ... pochissimi dispositivi ad alta velocità possono tollerare la doppia copia sul kernel, quindi l'utente in questi giorni. IANANG (I Am Not A Network Guru) ma credo che DMA sia usato in modo aggressivo –

+0

Quindi oggigiorno, una volta che una NIC cattura un pacchetto, sarà copiato direttamente nella memoria (utente)? – Rayne

+3

@ Rayne sì; la NIC utilizzerà il DMA per trasferire i dati direttamente nella memoria fisica mappata nello spazio degli indirizzi del processo (userland). – vladr

risposta

12

Come questo processo gioca fuori è per lo più l'autore del driver e l'hardware , ma per i piloti che ho guardato o scritta e l'hardware con cui ho lavorato, questo è di solito il modo in cui funziona:

  1. a inizializzazione del conducente, che assegnerà un certo numero di buffer e dare a questi a il NIC.
  2. Quando un pacchetto viene ricevuto dalla scheda NIC, estrae l'indirizzo successivo dal relativo elenco di buffer, inserisce i dati direttamente in esso e notifica il driver tramite un interrupt.
  3. Il driver riceve l'interrupt e può trasformare il buffer nel kernel oppure allocare un nuovo buffer del kernel e copiare i dati. "Zero copy networking" è il primo e ovviamente richiede supporto dal sistema operativo. (più in basso su questo)
  4. Il driver deve allocare un nuovo buffer (nel caso zero-copy) o riutilizzerà il buffer. In entrambi i casi, il buffer viene restituito alla scheda NIC per i pacchetti futuri.

La rete a zero copie all'interno del kernel non è poi così male. Zero-copia fino in fondo a terra utente è molto più difficile. Userland riceve i dati, ma i pacchetti di rete sono costituiti sia dall'intestazione che dai dati. Per lo meno, la vera copia zero verso l'utente richiede il supporto dalla scheda NIC in modo che possa pacchetti DMA in buffer di intestazione/dati separati. Le intestazioni vengono riciclate una volta che il kernel instrada il pacchetto verso la sua destinazione e verifica il checksum (per TCP, nell'hardware se la NIC lo supporta o nel software se non lo fa; nota che se il kernel deve calcolare il checksum stesso, sarebbe può anche copiare i dati: osservare i dati comporta perdite nella cache e copiarli altrove può essere gratuito con il codice sintonizzato).

Anche supponendo che tutte le stelle siano allineate, i dati non sono effettivamente nel buffer utente quando vengono ricevuti dal sistema. Fino a quando un'applicazione richiede i dati, il kernel non sa dove andrà a finire. Si consideri il caso di un demone multi-processo come Apache. Esistono molti processi figlio, tutti in ascolto sullo stesso socket. È inoltre possibile stabilire una connessione, fork(), ed entrambi i processi sono in grado di immettere recv() dati in entrata.

I pacchetti TCP su Internet sono in genere 1460 byte di payload (MTU di 1500 = 20 byte intestazione IP + 20 byte intestazione TCP + 1460 byte dati). 1460 non è una potenza di 2 e non corrisponde a una dimensione di pagina su nessun sistema che troverai. Questo presenta problemi per il riassemblaggio del flusso di dati. Ricorda che TCP è orientato al flusso. Non vi è alcuna distinzione tra le scritture del mittente e due scritture da 1000 byte in attesa verranno ricevute interamente in una lettura di 2000 byte.

Considerando ciò, considerare i buffer utente. Questi sono assegnati dall'applicazione. Per poter essere usato per zero-copy fino in fondo, il buffer deve essere allineato alla pagina e non condividere quella pagina di memoria con qualcos'altro. Al tempo recv(), il kernel potrebbe teoricamente rimappare la vecchia pagina con quella contenente i dati e "capovolgerla" in posizione, ma ciò è complicato dal problema del riassemblaggio visto che i pacchetti successivi si troveranno su pagine separate. Il kernel potrebbe limitare i dati che restituisce al carico utile di ogni pacchetto, ma ciò comporterà molte chiamate di sistema aggiuntive, rimappatura delle pagine e probabilmente una minore velocità complessiva.

Sto solo graffiando la superficie su questo argomento. Ho lavorato in un paio di società nei primi anni del 2000 cercando di estendere i concetti di copia zero in terra d'utenza. Abbiamo persino implementato uno stack TCP in userland e abbiamo eluso il kernel interamente per le applicazioni che utilizzavano lo stack, ma questo ha portato il suo insieme di problemi e non è mai stato di qualità di produzione. È un problema molto difficile da risolvere.