2016-04-14 14 views
6

Sto cercando di capire il concetto di descrittori Rx e Tx utilizzati nel codice del driver di rete.concetto descrittore in NIC

  1. Sono Descrittori nel software (RAM) o nell'hardware (scheda NIC).
  2. Come si riempiono.

MODIFICA: quindi in un codice del driver di scheda Realtek. Ho una struttura seguente definita.

struct Desc 
{ 
     uint32_t opts1; 
     uint32_t opts2; 
     uint64_t addr; 
}; 

txd->addr = cpu_to_le64(mapping); 
txd->opts2 = cpu_to_le32(opts2); 
txd->opts1 = cpu_to_le32(opts1 & ~DescOwn); 

così sono i opts1 and opts2 e là bit come DescOwn scheda specifica? Saranno definiti dal produttore nella scheda tecnica?

Grazie Nayan

risposta

24

Risposta rapida:

  1. Sono costrutti software che segue la definizione, da parte del NIC hardware in modo che entrambi capisce e potrebbe parlare tra loro.
  2. Vengono riempiti dal driver (ad esempio allocazione buffer vuoto RX) o da NIC (writeback RX). Vedi sotto per ulteriori dettagli.

piu 'dettagli architettonici:

Nota: I suppone che si abbia conoscenza della struttura di dati ad anello, il concetto di DMA. https://en.wikipedia.org/wiki/Circular_buffer

https://en.wikipedia.org/wiki/Direct_memory_access

Consideriamo percorso RX prima. Dopo aver ricevuto un pacchetto, la NIC traduce il segnale elettronico/ottico/radio sul cavo in byte di dati binari. Quindi la NIC deve informare l'OS che ha ricevuto qualcosa. Ai vecchi tempi, questo veniva fatto da interrupt e il sistema operativo leggeva i byte da una posizione predefinita sulla NIC alla RAM. Tuttavia questo è lento dal momento che 1) la CPU è necessaria per partecipare al trasferimento dei dati da NIC a RAM 2) potrebbero esserci molti pacchetti, quindi molte interruzioni che potrebbero essere troppe da gestire per la CPU. Quindi il DMA è arrivato e risolve il primo problema. Inoltre, la gente ha progettato il driver in modalità poll (o modalità ibrida, come in NAPI Linux) in modo che la CPU potesse essere liberata dalla gestione delle interruzioni e interrogare molti pacchetti contemporaneamente risolvendo così il secondo problema.

Il descrittore è un meccanismo che consente di semplificare facilmente la NIC. Come suggerisce il nome, descrive un pacchetto. Quindi non contiene dati a pacchetto (per NIC per quanto ne so), ma piuttosto descrive dove sono i dati. RX Descriptor Data Structure

Torniamo alla storia RX. La scheda NIC termina la traduzione in byte e vorrebbe fare un DMA in RAM. Ma prima, NIC ha bisogno di sapere dove DMA, in quanto non può mettere in modo casuale i dati nella RAM che CPU non saprà dove e non è sicuro.

Quindi durante l'inizializzazione della coda RX, il driver NIC pre-alloca un buffer di pacchetti, nonché una matrice di descrittori di pacchetti. Inizializza ogni descrittore di pacchetti in base alla definizione della NIC.

prendo driver Intel XL710 come un esempio di codice (alcune vars vengono rinominate per una migliore comprensione): XL710 Descriptor format

struct i40e_rx_queue { 
    struct packet_buffer_pool *pool; /* < packet pool */ 
    volatile i40e_16byte_rx_desc *rx_ring; /* < RX ring of descriptors */ 
    struct packet_buffer *pkt_addr_backup; /* save a copy of packet buffer address for writeback descriptor reuse */ 
.... 
} 

union i40e_16byte_rx_desc { 
    struct { 
     __le64 pkt_addr; /* Packet buffer address, points to a free packet buffer in packet_buffer_pool */ 
     __le64 hdr_addr; /* Header buffer address, normally isn't used */ 
    } read; /* initialized by driver */ 

    struct { 
     struct { 
      struct { 
       union { 
        __le16 mirroring_status; 
        __le16 fcoe_ctx_id; 
       } mirr_fcoe; 
       __le16 l2tag1; 
      } lo_dword; 
      union { 
       __le32 rss; /* RSS Hash */ 
       __le32 fd_id; /* Flow director filter id */ 
       __le32 fcoe_param; /* FCoE DDP Context id */ 
      } hi_dword; 
     } qword0; 
     struct { 
      /* ext status/error/pktype/length */ 
      __le64 status_error_len; 
     } qword1; 
    } wb; /* writeback by NIC */ 
}; 

enter image description here

  1. driver alloca un numero di buffer di pacchetto nella RAM (memorizzato nella struttura dati packet_buffer_pool).

    pool = alloc_packet_buffer_pool(buffer_size=2048, num_buffer=512); 
    
  2. driver inserisce l'indirizzo di ciascun buffer di pacchetto nel campo descrittore, come

    rx_ring[i]->read.pkt_addr = pool.get_free_buffer(); 
    
  3. driver indichi NIC la posizione iniziale della rx_ring, la sua lunghezza e testa/coda. Quindi la NIC saprebbe quali descrittori sono liberi (quindi il buffer di pacchetti puntato da quei descrittori è gratuito). Questo processo viene eseguito dal conducente che scrive tali informazioni nei registri NIC (fissi, potrebbero essere trovati nella scheda tecnica NIC).

    rx_ring_addr_reg = &rx_ring; 
    rx_ring_len_reg = sizeof(rx_ring); 
    rx_ring_head = 0; /* meaning all free at start */ 
    /* rx_ring_tail is a register in NIC as NIC updates it */ 
    
  4. Ora NIC sa che descrittore rx_ring [{x, y, z}] sono libere e nuovi dati a pacchetto {x, y, z} .pkt_addr possono essere dedicate. Va avanti e DMA nuovi pacchetti in {x, y, z} .pkt_addr. Nel frattempo, NIC poteva pre-processare (offload) l'elaborazione dei pacchetti (come la verifica della somma di controllo, estrarre il tag VLAN), quindi avrebbe anche bisogno di un posto dove lasciare quelle informazioni per il software. In questo caso, i descrittori vengono riutilizzati per questo scopo nel writeback (vedere la seconda struttura nell'unione dei descrittori). La NIC fa avanzare l'offset del puntatore di coda rx_ring, indicando che un nuovo descrittore è stato riscritto da NIC. [Un trucco qui è che, poiché i descrittori sono riutilizzati per i risultati pre-processo, il driver deve salvare {x, y, z}. pkt_addr in una struttura dati di backup].

    /* below is done in hardware, shown just for illustration purpose */ 
    if (rx_ring_head != rx_ring_tail) { /* ring not full */ 
        copy(rx_ring[rx_ring_tail].read.pkt_addr, raw_packet_data); 
        result = do_offload_procesing(); 
    
        if (pre_processing(raw_packet_data) & BAD_CHECKSUM))  
         rx_ring[rx_ring_tail].writeback.qword1.stats_error_len |= RX_BAD_CHECKSUM_ERROR; 
        rx_ring_head++; /* actually driver sets a Descriptor done indication flag */ 
            /* along in writeback descriptor so driver can figure out */ 
            /* current HEAD, thus saving a PCIe write message */ 
    } 
    
  5. driver legge il nuovo puntatore coda offset e trovato {x, y, z} sono nuovi pacchetti. Rileva il pacchetto da pkt_addr_backup [{x, y, z}] e dai relativi risultati di pre-precessione.

  6. Quando il software del livello superiore viene eseguito con i pacchetti, {x, y, z} verrebbe reimpostato su rx_ring e il puntatore della testa dell'anello verrà aggiornato per indicare i descrittori liberi.

Questo conclude il percorso RX. Il percorso TX è praticamente inverso: il livello superiore produce pacchetti, i dati del pacchetto di copia del driver in packet_buffer_pool e lascia che tx_ring [x] .buffer_addr punti ad esso. Il driver prepara anche alcuni flag di offload TX (come checksum hardware, TSO) nel descrittore TX. La NIC legge il descrittore TX e DMA tx_ring [x] .buffer_addr dalla RAM alla NIC.

Queste informazioni vengono normalmente visualizzate nella scheda tecnica NIC, come Intel XL710 xl710-10-1040-controller-scheda tecnica, capitolo 8.3 & 8.4 Percorso dati RX/TX LAN.

http://www.intel.com/content/www/us/en/embedded/products/networking/xl710-10-40-controller-datasheet.html

Inoltre è possibile controllare il codice driver open source (sia del kernel Linux o qualche libreria user space come DPDK PMD), che conterrebbe descrittore definizione struct.

Btw, suggerisco di taggare anche la domanda con "Rete".

- Modifica 1 -

Per la vostra domanda aggiuntiva per quanto riguarda il driver Realtek: Sì, quei bit sono NIC specifica. Un suggerimento è linee come

desc->opts1 = cpu_to_le32(DescOwn | RingEnd | cp->rx_buf_sz); 

DescOwn è un flag di bit che modificando dice NIC che ora possiede questo descrittore e relativo buffer. Inoltre ha bisogno di convertire da endianness della CPU (potrebbe essere power CPU, che è BE) a Little Endian che NIC accetta di capire.

È possibile trovare le informazioni rilevanti in http://realtek.info/pdf/rtl8139cp.pdf (ad esempio Pagina 70 per DescOwn), sebbene non sia così come XL710 ma almeno contenga tutte le informazioni di registro/descrittore.

- Modifica 2 -

Il descrittore NIC è una definizione molto dipende fornitore. Come mostrato sopra, il descrittore NIC di Intel utilizza lo stesso anello descrittore RX RX per fornire i buffer NIC su cui scrivere e per la NIC per scrivere informazioni RX. Esistono altre implementazioni come la coda di invio/completamento RX suddivisa (più diffusa nella tecnologia NVMe). Ad esempio, alcune schede NIC di Broadcom hanno un singolo anello di sottomissione (per fornire un buffer alla scheda NIC) e un anello di completamento multiplo. È progettato per la decisione della NIC e mette i pacchetti in un anello diverso per es. diversa priorità della classe di traffico, in modo che il conducente possa ottenere prima i pacchetti più importanti. enter image description here (Da Guida BCM5756M NIC Programmer)

--edit 3--

Trovo in generale NIC scheda tecnica di Intel di essere più aperta e informativo sul loro design. Un breve riassunto del flusso Tx/Rx è descritto nella scheda tecnica della famiglia Intel 82599, sezione 1.8 Architettura e operazioni di base.

+0

Giusto per chiarire, si prega di vedere la modifica alla domanda !! – Haswell

+0

Vedi la mia modifica. Grazie. –