3.3 Uno sguardo nel kernel FreeBSD
3.3.3 Le interfacce di rete e il processo di spedizione
Il metodo utilizzato da FreeBSD per gestire le interfacce di rete `e quello di associare a ciascuna di esse una struttura dati ifnet che raccoglie, in maniera ordinata, tutte le informazioni necessarie. Alcune di esse sono le seguenti:
if softc: Puntatore ad una struttura privata del driver (dipendente dal- l’hardware);
if l2com: Puntatore ad una struttura contenente informazioni di livello 2;
if xname: Nome dell’interfaccia nel sistema;
if dname: Nome del driver che gestisce l’interfaccia;
if addrhead: Testa della lista degli indirizzi assegnati a questa interfaccia;
if flags: Flags che descrivono parametri operazionali dell’interfaccia (mani- polati dal codice generico);
if drv flags: Flags che descrivono lo stato operazionale dell’interfaccia (ma- nipolati dal driver);
if capabilities: Flags che descrivono le capabilities supportate;
if capenable: Flags che descrivono le capabilities abilitate;
if data: Struttura contenente informazioni statistiche;
Oltre a queste ce ne sono anche altre, ma `e importante soffermarsi su due in particolare.
La prima `e la coda di output if snd nella quale vengono inseriti i pac- chetti al termine delle operazioni di processing dello stack e prima che il driver provveda a trasferirli.
3.3. UNO SGUARDO NEL KERNEL FREEBSD 33
La seconda sono i puntatori alle funzioni specifiche del driver previste dall’interfaccia standard. Tra queste `e importante ricordare:
if output: Fa procedere l’output del pacchetto verso l’interfaccia;
if transmit: Si occupa di trasmettere il pacchetto o di accodarlo se l’inter- faccia `e gi`a in uso;
if start: Avvia il trasferimento dei pacchetti accodati sulla if snd verso la scheda di rete;
Relativamente ai flags del campo if drv flags ce ne sono due di parti- colare interesse:
IFF DRV RUNNING: Viene settato al completamento delle operazioni di setup del driver ed indica che l’interfaccia `e in grado di operare;
IFF DRV OACTIVE: Viene settato dal driver in caso di esaurimento delle risorse hardware dell’interfaccia;
Con questi elementi ed osservando la figura 3.2 `e possibile illustrare in maniera semplificata il percorso seguito da un pacchetto attraverso lo stack di rete, fino al livello del driver. Esso ha inizio con la chiamata, da parte del generatore, della ip output. Il pacchetto poi, dopo aver subito le manipolazioni di livello IP, attraverso il metodo if output raggiunge il livello ethernet, dove viene ulteriormente processato. Infine, per mezzo della funzione if transmit vengono eseguite le due macro riportate nel listing 3.5. La seconda in particolare si occupa di inserire il pacchetto nella coda if snd, quindi, a seconda dell’esito di questa operazione e della disponibilit`a di risorse hardware, di avviare il trasferimento alla scheda attraverso la if start.
34 CAPITOLO 3. IMPLEMENTAZIONE E TEST
Figura 3.2: Schema del funzionamento del sistema durante la spedizione di un pacchetto.
I driver delle schede di rete, pur presentando tra loro delle evidenti ana- logie dal punto di vista strutturale e da quello dei meccanismi utilizzati, restano strettamente legati alle caratteristiche del proprio hardware. Pro- seguiremo quindi nella descrizione del driver che gestisce l’interfaccia utiliz- zata nei test e che si chiama em. Relativamente ad esso ci soffermeremo principalmente sulla parte che si occupa del trasferimento dei dati.
La comunicazione del driver con la scheda avviene in parte attraverso delle operazioni di I/O nei registri ed in parte attraverso degli accessi in DMA alla memoria principale. In quest ultimo caso, un ruolo importante `e ricoperto dal vettore dei buffer e da quello dei descrittori. Essi vengono allocati dal driver durante le operazioni di setup ed hanno una lunghezza variabile a seconda dello spazio di memorizzazione disponibile sulla scheda. Il vettore dei descrittori, noto anche come ring per via del suo utilizzo in maniera circolare, rappresenta la coda fisica di trasmissione. Il suo indirizzo iniziale, la lunghezza ed i puntatori alla testa e alla coda vengono quindi
3.3. UNO SGUARDO NEL KERNEL FREEBSD 35
Listing 3.5: Macro di accodamento dei pacchetti nella if snd.
#define IFQ HANDOFF( i f p , m, e r r ) \
IFQ HANDOFF ADJ( i f p , m, 0 , e r r )
#define IFQ HANDOFF ADJ( i f p , m, adj , e r r ) \
do { \ i n t l e n ; \ short m f l a g s ; \ \ l e n = (m)−>m pkthdr . l e n ; \ m f l a g s = (m)−> m f l a g s ; \ IFQ ENQUEUE(&( i f p )−> i f s n d , m, e r r ) ; \ i f ( ( e r r ) == 0 ) { \ ( i f p )−> i f o b y t e s += l e n + ( a d j ) ; \ i f ( m f l a g s & M MCAST) \ ( i f p )−> i f o m c a s t s ++; \
i f ( ( ( i f p )−> i f d r v f l a g s & IFF DRV OACTIVE) == 0 ) \
i f s t a r t ( i f p ) ; \
} \
} while ( 0 )
memorizzati in appositi registri della scheda. Il processo di spedizione dei pacchetti a livello driver pu`o essere sintetizzato brevemente nei seguenti passi:
1. Il driver preleva un pacchetto dalla coda di output (if snd), lo inserisce all’interno di uno o pi`u buffer ed imposta i descrittori corrispondenti. Ciascun descrittore, infatti, punta ad un buffer distinto. Successiva- mente aggiorna il registro contenente il puntatore alla coda del ring per notificare alla scheda la presenza di un nuovo pacchetto da spedire.
2. La scheda ne prende atto quindi inizia ad analizzare uno per volta i descrittori disponibili. Per ciascuno di essi viene recuperato dal- la memoria il buffer associato e poi viene settato un bit di stato. Successivamente viene fatto avanzare il puntatore alla testa del ring.
36 CAPITOLO 3. IMPLEMENTAZIONE E TEST
pacchetto, pu`o iniziare a trasmetterlo sul link. Allo stesso tempo viene generato un interrupt hardware per consentire al driver di rilasciare i buffer ed i descrittori coinvolti nel trasferimento corrente.
Riprendendo lo schema in figura3.2, con la chiamata alla if start viene mandato in esecuzione il metodo em start del driver, il cui funzionamento `e riportato in figura3.3.
Figura 3.3: Schema di funzionamento del metodo em start.
Nel caso in cui la start esca dal ciclo per mancanza di descrittori viene anche settato il flag IFF DRV OACTIVE.
La funzione em xmit si occupa di effetturare il mapping di un pac- chetto su dei buffer e dei descrittori residenti in memoria. Successivamente provvede a far avanzare il puntatore alla coda del ring.
Il metodo em txeof si occupa invece di analizzare il ring e liberare i buffer e i descrittori gi`a processati dalla scheda. Al termine di questa operazione di pulizia, se il numero dei descrittori disponibili `e salito ad un valore superiore alla soglia EM TX CLEANUP THRESHOLD viene ripulito
3.3. UNO SGUARDO NEL KERNEL FREEBSD 37
anche il flag IFF DRV OACTIVE dell’interfaccia. Il valore di default a cui `e impostata la soglia EM TX CLEANUP THRESHOLD nel driver `e pari a 1/8 del numero totale dei descrittori.
L’operazione di dequeue sulla if snd richiede degli ulteriori chiarimenti. Tale coda infatti `e realizzata con una struttura di tipo ifaltq. Essa consen- te, al suo interno, un ulteriore livello di accodamento attraverso una parte riservata al driver, come visibile in figura3.4.
Figura 3.4: Rappresentazione schematica della coda if snd.
Le operazioni di enqueue e dequeue quindi seguono il comportamento specificato nello pseudocodice in figura3.5.
Figura 3.5: Comportamento di enqueue e dequeue sulla if snd.
Il trasferimento di pacchetti dalla coda A a quella B ha termine con l’esaurimento di quelli presenti in A oppure con il raggiungimento della dimensione massima prevista per la B.
La parte del driver appena descritta, poich´e mandata in esecuzione dal metodo if start, pu`o essere considerata sincrona con il funzionamento del ge- neratore. Tuttavia, `e presente anche una parte che viene eseguita in modalit`a
38 CAPITOLO 3. IMPLEMENTAZIONE E TEST
asincrona e concorrente rispetto ad essa e legata all’arrivo degli interrupt. Nel driver em, questa parte viene gestita attraverso l’uso delle taskqueue. Queste sono delle particolari code sulle quali `e possibile inserire dei task da mandare in esecuzione all’arrivo di determinati segnali. Nel nostro caso sono previste due taskqueue ed i due task riportati in figura3.6.
Figura 3.6: Comportamento dei task di interruzione.
La funzione em start locked ha un comportamento equivalente alla em start ma non si occupa di acquisire inizialmente e rilasciare alla fine il lock sul ring.
Il task em msix tx viene inserito nella prima taskqueue ed eseguito all’arrivo dell’interrupt di fine trasmissione.
L’ em handle tx pu`o essere schedulato dal primo per un istante suc- cessivo attraverso l’accodamento sull’altra taskqueue.
La frequenza di arrivo degli interrupt introduce un ben noto trade-off. Se troppo elevata, da un lato favorisce le operazioni di rilascio delle risor- se, ma dall’altro, con i cambiamenti di contesto che comporta, introduce un overhead consistente. A tal fine, il driver em prevede un meccanismo di interrupt moderation. In fase di inizializzazione viene impostata in un registro la frequenza massima con cui possono essere lanciati gli interrupt. Cos`ı facendo verranno eseguite meno operazioni di pulizia ma saranno pi`u fruttuose e comporteranno globalmente un costo computazionale minore.