Avanti Indietro Indice

8. Informazioni tecniche

Queste informazioni saranno utili a quanto vogliono capire un po' meglio come funziona la loro scheda, oppure vogliono giocare con il driver o anche provare a fare il loro driver personale per una scheda che attualmente non è supportata. Se non si cade in queste categorie, allora si può pure saltare questa sezione.

8.1 I/O programmato, memoria condivisa e DMA a confronto

Se già si ricevono e inviano pacchetti back-to-back (NdT letteralmente ``uno dopo l'altro''), non si possono mettere altri bit nel cavo. Ogni scheda Ethernet moderna può ricevere pacchetti back-to-back. I driver per Linux per DP8390 (wd80x3, SMC-Ultra, 3c503, ne2000, ecc.) arrivano abbastanza vicino all'invio di pacchetti back-to-back (il limite è dato dalla reale latenza degli interrupt) e l'hardware 3c509 e AT1500 non ha problemi ad inviare automaticamente pacchetti back-to-back.

Il bus ISA può fare 5.3MB/sec (42Mb/sec), che sembra più che sufficiente per una Ethernet a 10Mbps. Nel caso di schede a 100Mpbs, chiaramente è necessario un bus più veloce per sfruttare la larghezza di banda della rete.

I/O programmato (Programmed I/O) (es. NE2000, 3c509)

Pro: Non usa nessuna risorsa di sistema riservata, solo alcuni registri di I/O e non ha il limite dei 16M.

Contro: Solitamente più bassa è la velocità di trasferimento, più la CPU attende senza far niente, e l'accesso ai pacchetti interleaved è solitamente difficile se non impossibile.

Memoria condivisa (Shared memory) (es. WD80x3, SMC-Ultra, 3c503)

Pro: Più veloce e semplice dell'I/O programmato e inoltre permette l'accesso casuale ai pacchetti. Dove possibile, i driver per Linux calcolano il checksum dei pacchetti IP in ingresso non appena sono copiati fuori dalla scheda. Tale cosa risulta in un'ulteriore riduzione dell'uso della CPU rispetto ad una equivalente scheda PIO.

Contro: Usa maggiore spazio di memoria (molto grande per gli utenti DOS, essenzialmente non problematico sotto Linux) e usa ancora parecchio la CPU.

Accesso diretto alla memoria (DMA) di tipo slave (normale) (non per Linux!)

Pro: Libera la CPU durante il reale trasferimento dei dati.

Contro: Il controllo delle condizioni al contorno, l'allocazione di buffer contigui e la programmazione dei registri DMA la rende la tecnica più lenta fra tutte. Inoltre satura facilmente un canale DMA e richiede buffer allineati in memoria bassa.

Accesso diretto alla memoria (DMA) di tipo bus master (es. LANCE, DEC 21040)

Pro: Libera la CPU durante il trasferimento dei dati, può legare assieme i buffer, nel bus ISA può richiede una piccola (nulla) perdita del tempo di CPU. La maggior parte dei driver per Linux bus-master usano lo schema `copybreak' nel quale i grossi pacchetti sono messi direttamente dalla scheda nel buffer di rete del kernel, e i pacchetti piccoli sono copiati invece dalla CPU che li carica in cache per le eleborazioni successive.

Contro: (Applicabile solamente alle schede per bus ISA) Per la scheda sono necessari buffer in memoria bassa e di canali DMA. Qualsiasi dispositivo bus-master avrà problemi con altri dispositivi non bus-master che si appropriano del bus, come alcuni primitivi adattatori SCSI. Alcuni chipset delle schede madri mal progettati hanno problemi con il bus-master. Una ragione per non usare alcun tipo di dispositivo DMA è un processore 486 progettato come rimpiazzo di un 386: questi processori devono scaricare la loro cache ad ogni ciclo di DMA (fra questi ci sono Cx486DLC, Ti486DLC, Cx486SLC, Ti486SLC, ecc.)

8.2 Scrivere un driver

La sola cosa che serve per usare una scheda Ethernet con Linux è il driver appropriato. Per questo è essenziale che i costruttori rilascino le informazioni tecniche di programmazione al pubblico senza che qualcuno debba vendersi per vita per averle. Un buon esempio sulla possibilità di ottenere documentazione (oppure se non si sta scrivendo codice, sulla possibilità che qualcun'altro scriverà quel driver di cui si ha veramente bisogno) è la disponibilità del packet driver Crynwr (nato Clarkson). Russ Nelson guida questa operazione ed è stato molto d'aiuto nel supportare lo sviluppo dei driver per Linux. I net-surfer possono provare questo URL per vedere il software di Russ.

Russ Nelson's Packet Drivers

Avuta la documentazione si può scrivere un driver per la propria scheda e usarlo per Linux (almeno in teoria). Si tenga presente che alcuni dei vecchi hardware che erano stati pensati per macchine di tipo XT non funzioneranno molto bene in un ambiente multitasking come Linux. L'uso di uno di questi comporterà non pochi problemi se la propria rete deve sostenere un traffico ragionevole.

La maggior parte delle schede ha dei driver per le interfacce MS-DOS come NDIS o ODI, ma questi sono inutili per Linux. Molti hanno suggerito di fare il link direttamente di questi o utilizzare una traduzione automatica, ma queste sono cose praticamente impossibili. I driver MS-DOS si aspettano di essere in modalità a 16 bit e si basano su `interrupt software', cose che sono entrambe incompatibili con il kernel di Linux. Questa incompatibilità è in realtà una caratteristica di Linux, in quanto alcuni driver per Linux sono spesso decisamente migliori delle loro controparti MS-DOS. La serie `8390' dei driver, per esempio usa un buffer di trasmissione ping-pong, che ora è stato introdotto anche nel mondo MS-DOS.

(Buffer Tx di tipo ping-pong significa usare almeno due buffer di pacchetti per i pacchetti da trasmettere. Uno è caricato mentre la scheda sta trasmettendo l'altro. Il suo contenuto viene poi trasmesso non appena è conclusa la trasmissione dell'altro e così via. In questo modo, la maggior parte delle schede sono in grado di inviare continuamente pacchetti back-to-back nel cavo.)

OK. Quindi si è deciso che si vuole scrivere un driver per la scheda Ethernet CippaLippa, poiché si possiedono le informazioni di programmazione e nessuno l'ha ancora fatto (... queste sono le due condizioni principali ;-) Si dovrebbe partire dallo scheletro per un driver di rete fornito assieme ai sorgenti di Linux. Può essere trovato nel file /usr/src/linux/drivers/net/skeleton.c in tutti i kernel recenti. Si dia un'occhiata anche alla Kernel Hackers Guide, a questo indirizzo: KHG

8.3 Interfaccia dei driver verso il kernel

Ecco alcune note sulle funzioni che si dovranno scrivere se si crea un nuovo driver. Si leggano queste cose assieme allo scheletro del driver citato prima per aiutarsi a chiarire un po' le cose.

Probe (rilevamento)

È chiamata all'avvio per controllare l'esistenza della scheda. Meglio se si può farlo non intrusivamente leggendo dalla memoria, ecc. Può anche leggere dalle porte I/O. La scrittura iniziale nelle porte di I/O durante il probe non è una buona cosa in quanto può uccidere un altro dispositivo. Una parte dell'inizializzazione del dispositivo è fatta qui (allocando lo spazio I/O, IRQ, riempendo i campi di dev->???, ecc). Si deve sapere a quali porte di I/O o zone di memoria può essere configurata la scheda, come abilitare la memoria condivisa (se usata), come selezionare/abilitare la generazione degli interrupt, ecc.

Interrupt handler (gestore dell'interrupt)

È chiamato dal kernel quando la scheda genera un interrupt. Ha il compito di determinare perché la scheda lo ha generato e comportarsi di conseguenza. Le usuali condizioni di interrupt sono la ricezione di dati, il completamento della trasmissione, la segnalazione di condizioni d'errore. Si deve conoscere ogni bit di stato dell'interrupt di una qualche importanza in modo da portersi comportare di conseguenza.

Funzione transmit

È collegata a dev->hard_start_xmit() ed è chiamata dal kernel quando ci sono alcuni dati che il kernel vuole depositare nel dispositivo. Mette i dati nella scheda e avvia la trasmissione. Si deve sapere come raccogliere i dati, come metterli dentro la scheda (copia della memoria condivisa, trasferimento PIO, DMA?) e il posto giusto dove metterli. Poi si deve sapere come dire alla scheda di inviare i dati nel cavo e (possibilmente) sollevare un interrupt quando ha fatto. Quando l'hardware non può accettare ulteriori pacchetti dovrebbe impostare il flag dev->tbusy. Quando è disponibile dello spazio, solitamente durante un interrupt per il completamento della trasmissione, dev->tbusy dovrebbe essere liberato e i livelli più elevati informati con mark_bh(INET_BH).

Funzione receive

È chiamata dall'interrupt handler del kernel quando ci sono dei dati nella scheda. Toglie i dati dalla scheda, li impacchetta in un sk_buff e informa il kernel che i dati sono lì, dimodoché questo possa fare una netif_rx(sk_buff). Si deve sapere come abilitare la generazione di un interrupt sulla ricezione di dati, come controllare qualsiasi bit di stato della ricezione e come togliere i dati dalla scheda (ancora memoria condivisa, PIO, DMA, ecc.).

Funzione open

È collegata a dev->open ed è chiamata dagli strati di rete quando qualcuno fa ifconfig eth0 up per attivare il dispositivo ed abilitarlo per la Rx/Tx di dati. Qualsiasi inizializzazione speciale che non viene fatta nella sequenza di probe (abilitare la generazione degli IRQ, ecc.) dovrebbe andare qui.

Funzione close (opzionale)

Questa mette la scheda in uno stato decente quando qualcuno fa ifconfig eth0 down. Dovrebbe liberare gli IRQ e i canali DMA se l'hardware lo permette e disabilitare qualsiasi cosa che possa far risparmiare corrente (come il transceiver).

Funzioni varie

Cose come una funzione di reinizializzazione, cosicché se le cose vanno male, il driver può provare, come ultima risorsa, a ripristinare la scheda. Solitamente è fatto quando una trasmissione va in time out o cose simili. Può essere utile anche una funzione per leggere i registri di statistica delle scheda (se ce li ha).

8.4 Informazioni tecniche dalla 3Com

Se si è interessati a lavorare su un driver per una scheda 3Com, si possono ottenere informazioni tecniche direttamente dalla 3Com. Cameron è stato talmente gentile da spiegarci come averle:

«Gli adattatori Ethernet della 3Com sono documentati per chi vuole scrivere un driver nei nostri `Technical Reference' (TR). Questi manuali descrivono le interfacce di programmazione delle schede ma non parlano della diagnostica, programmi d'installazione, ecc. tutte quelle cose che interessano all'utilizzatore finale.

I TR sono distribuiti dal dipartimento di marketing della Network Adapter Division. Per far funzionare le cose in maniera efficiente, la distribuzione è centralizzata in una cosa detta `CardFacts'. CardFacts è un sistema telefonico automatizzato. Se lo si chiama con un telefono a toni può inviare fax dove si richiede. Per ottenere un TR, si chiami CardFacts al 408-727-7021. Gli si chieda il ``Developer's Order Form'' (modulo d'ordine per sviluppatori), documento numero 9070. Si tenga sotto mano il proprio numero di fax quando si chiama. Si compili il modulo d'ordine e lo si invii via fax al 408-764-5004. I manuali sono spediti con il servizio ``2nd Day'' della Federal Express.

Alcuni pensano che diamo via troppo facilmente i manuali e cercano prove per dire il sistema è troppo costoso e che occupa troppo tempo e sforzi. Da tempo, i nostri clienti sono sempre stati contenti di questa cosa e non ci sono mai stati problemi nonostante le quantità di richieste che riceviamo. Abbiamo bisogno della loro continua cooperazione e riserbo per mantenere le cose così.»

8.5 Note sulle schede basate su PCnet / LANCE di AMD

Il chip LANCE (Local Area Network Controller for Ethernet) era l'offerta originale dell'AMD e da allora è stato rimpiazzato dal chip `PCnet-ISA', noto anche come 79C960. Si noti che il nome `LANCE' è stuck e alcuni ancora fanno riferimento ai nuovi chip con il vecchio nome. Dave Roberts della Network Products Division di AMD è stato talmente gentile da fornire le seguenti informazioni riguardo questo chip:

«Funzionalmente, è equivalente a una NE1500. L'insieme dei registri è indentico a quello del vecchi LANCE con le aggiunte dell'architettura 1500/2100. I vecchi driver per 1500/2100 funzioneranno anche con il PCnet-ISA. L'architettura degli NE1500 e degli NE2100 in pratica è la stessa. Inizialmente la Novell l'ha chiamata 2100, ma hanno poi provato a distinguere tra le schede per il coassiale e le 10Base-T. Qualsiasi cosa che era solamente 10Base-T è stata numerata nell'intervallo 1500. Questa è la sola differenza.

Molte compagnie offrono prodotti basati su PCnet-ISA, incluse HP, Racal-Datacom, Allied Telesis, Boca Research, Kingston Technology, ecc. Le schede in pratica sono le stesse se non per il fatto che alcuni costruttori hanno aggiunte le caratteristiche `jumperless' (senza ponticelli) che permettono la configurazione via software. La maggior parte non l'ha fatto. L'AMD offre un progetto standard per una scheda che usa il chip PCnet-ISA e molti costruttori usano il nostro progetto senza modifiche. Questo significa che chiunque voglia scrivere dei driver per la maggior parte delle schede basate su PCnet-ISA può semplicemente prendere il data-sheet dall'AMD. Si chiami il nostro centro di distribuzione della documentazione al (800)222-9323 e si chieda del data sheet per il Am79C960, il chip PCnet-ISA. È gratis.

Un modo veloce per capire se la scheda è una di quelle basate sul progetto standard, è quello di osservarla. Se è una standard, dovrebbe avere un grosso chip, un cristallo, una piccola PROM d'indirizzo IEEE, probabilmente un socket per una ROM di boot e un connettore (1, 2 o 3 a seconda dei mezzi supportati). Si noti che se è una scheda per cavo coassiale, avrà anche un po' di roba per il trasceiver, ma dovrebbe essere nei pressi del connettore e ben distante dal PCnet-ISA.»

Una nota per gli aspiranti hacker è che differenti implementazioni del LANCE effettuano il `restart' (riavvio) in modi diversi. Alcune riprendono da dove sono state interrotte, mentre altre ripartono dall'inizio, come se fossero state inizializzate.

8.6 Multicast e modalità promiscua

Un'altra delle cose a cui ha lavorato Donald è l'implementazione degli ``agganci'' (hook) per il multicast e la modalità promiscua (promiscuous mode). Tutti i driver ISA rilasciati (cioè non ALPHA) ora supportano la modalità promiscua.

Donald scrive: «Inizierei con il parlare della modalità promiscua, che concettualmente è facile da implementare. Per la maggior parte dell'hardware semplicemente si deve impostare un bit di registro e da allora si riceveranno tutti i pacchetti che passano su quel cavo. Beh, non è proprio così facile: per alcune schede si deve disabilitare la scheda (potenzialmente perdendo alcuni pacchetti), riconfigurarla e poi riabilitarla. OK, visto che questo è facile, adesso passo a qualcosa che non è proprio così ovvia: il multicast. Può essere fatto in due modi:

  1. Usando la modalità promiscua e un filtro di pacchetti come il Berkeley packet filter (BPF). Il BPF è un linguaggio stack di pattern matching (ricerca delle corrispondenze), dove si scrive un programma che raccoglie gli indirizzi ai quali si è interessati. Il suo vantaggio è che è molto generale e programmabile. Lo svantaggio è che non c'è un metodo generale per il kernel per evitare di attivare la modalità promiscua e far passare ogni pacchetto che attraversa il cavo su ognuno dei filtri di pacchetti registrati. Si veda Il Berkeley Packet Filter per maggior informazioni.
  2. Usare il filtro multicast su scheda che hanno la maggior parte delle schede.

Immagino che dovrei elencare quel poco che mettono a disposizione le schede o i chip:


Chip/scheda  Promiscua  Filtro multicast
-----------------------------------------
Seeq8001/3c501  Sì     Filtro binario (1)
3Com/3c509      Sì     Filtro binario (1)
8390            Sì     Hash a sei bit con Autodin II (2) (3)
LANCE           Sì     Hash a sei bit con Autodin II (2) (3)
i82586          Sì     Hash a sei bit con Hidden Autodin II (2) (4)

  1. Queste schede affermano di avere un filtro, ma è un semplice sì/no: «accetta tutti i pacchetti multicast» o «non accettare i pacchetti multicast».
  2. AUTODIN II è il polimonio di CRC (codice ciclico a ridonadanza) standard di Ethernet. In questo schema, degli indirizzi multicast viene calcolata l'hash e vengono poi ricercati in una tabella hash. Se è abilitato il bit corrispondente del pacchetto, allora questo è accettato. I pacchetti Ethernet sono progettati in modo che l'hardware per fare questa cosa sia banale: semplicemente si memorizzano i sesti bit del circuito CRC (comunque necessario per il controllo degli errori) dopo i primi sei otteti (l'indirizzo di destinazione) e li si usa per indicizzare nella tabella hash (sei bit: una tabella a 64 bit).
  3. Questi chip usano la hash a sei bit e la tabella dev'essere calcolata e caricata dall'host. Questo significa che il kernel deve contenere il codice per il CRC.
  4. Il 82586 usa la hash a sei bit internamente, ma calcola da solo la tabella di hast dall'elenco degli indirizzi multicast da accettare.

Si noti che nessuno di questi chip fa un filtraggio perfetto e c'è ancora bisogno di un modulo a livello intermedio per fare il filtraggio finale. Si noti pure che in tutti i casi si deve mantenere un'elenco completo degli indirizzi multicast accettati per ricalcolare la tabella di hash quando cambia.

8.7 Berkeley Packet Filter (BPF)

L'idea diffusa fra gli sviluppatori è che le funzionalità BPF non dovrebbero essere fornite dal kernel, ma dovrebbero essere in una libreria di compatibilità (si spera poco usata).

Per quelli che non lo conoscono, il BPF (Berkeley Packet Filter -- filtro dei pacchetti di Berkeley) è un meccanismo per specificare agli strati di rete del kernel i pacchetti ai quali si è interessati. È implementato come un interprete specializzato di un linguaggio stack costruito dentro il codice di rete a basso livello. Un'applicazione passa un programma scritto in questo linguaggio al kernel ed il kernel esegue il programma su ciascun pacchetto in ingresso. Se il kernel ha più applicazioni BPF, ogni programma è eseguito su ogni pacchetto.

Il problema è che è difficile dedurre dal programma di filtraggio dei pacchetti a quale tipo di pacchetti l'applicazione è veramente interessata, e quindi la soluzione generale è di eseguire sempre il filtro. Si immagini un programma che registra un programma BPF per raccogliere il flusso a bassa velocità inviato ad un indirizzo multicast. La maggior parte delle schede hanno un filtro hardware per indirizzi multicast implementato come una tabella di hash a 64 voci che ignora i pacchetti multicast maggiormente non voluti. Quindi c'è la possibilità di rendere questa operazione poco costosa. Ma con il BPF il kernel deve passare l'interfaccia in modalità promiscua, ricevere _tutti_ i pacchetti e farli passare attraverso il filtro. Questa cosa funziona, ma quel che è difficile è darne conto al processo che ha richiesto i pacchetti.


Avanti Indietro Indice