前言
此文是5、6年前维护网卡驱动和优化时记录总结,当时10G设备绝对主流,1G网卡还分单队列和多队列两种,几年过去网络设备上40G网卡大行其道,100G网卡也是纷至沓来,但不管带宽如何升级,其实现原理类似。
正传
ixgbe.h 定义的 的相关结构:
/*
-
The transmit ring, one per queue
*/
struct tx_ring {
struct adapter *adapter;
struct mbuf *m_prev;
struct mtx tx_mtx;
u32 me;
u16 queue_status;
u16 queue_full;
int watchdog_time;
union ixgbe_adv_tx_desc *tx_base; —>这是网卡真正是识别的discripter. 由ixgbe_dma_malloc函数分配4096个描述符(存储在连续的物理地址上), 该字段存储的是物理地址,在ixgbe_xmit的时候 操作 tx_base[i].read.buffer_addr = mbuf->m_data &~ DMAP_MIN_ADDRESS, 由此让网卡能够知道发送位置
struct ixgbe_dma_alloc txdma;
u32 next_avail_desc;
u32 next_to_clean;
struct ixgbe_tx_buf *tx_buffers; —>和描述符一样也是申请4096个,但是该成员是被用来操作驱动代码里面的mbuf的, 如在ixgbe_xmit里面tx_buffers[i]->m_head = mbuf(传进来的mbuf) 记录要发送的mbuf, 然后在ixgbe_txeof里面 把已经发送出去的mbuf内存回收,m_freem(tx_buffers[i]->m_head)
volatile u16 tx_avail
u32 txd_cmd;
bus_dma_tag_t txtag;
char mtx_name[16];u32 bytes; /* used for AIM /
u32 packets;
/ Soft Stats */
u64 no_desc_avail;
u64 total_packets;
};
/*
-
The Receive ring, one per rx queue
*/
struct rx_ring {
struct adapter *adapter;
struct mtx rx_mtx;
u32 me;
union ixgbe_adv_rx_desc *rx_base;-------------->这是网卡真正是识别的discripter. 由ixgbe_dma_malloc函数分配4096个描述符(存储在连续的物理地址上), 该字段存储的是物理地址,在setup和 refresh的时候 操作 rx_base[i].read.pkt_addr = mbuf->m_data &~ DMAP_MIN_ADDRESS, 由此让网卡能够找到接收位置, 在ixgbe_rxeof里面 通过rx_base[i] 拿到要处理的描述符,判断 vtag 类的信息 和 接收是否完成等
struct ixgbe_dma_alloc rxdma;
struct lro_ctrl lro;
bool lro_enabled;
bool hdr_split;
bool hw_rsc;
bool discard;
u32 next_to_refresh;
u32 next_to_check;
char mtx_name[16];
struct ixgbe_rx_buf *rx_buffers; ----------------->和描述符一样也是申请4096个,但是该成员是被用来操作驱动代码里面的mbuf的, 如在ixgbe_rxeof里面 通过拿到 rx_buffers[i] 一下就拿到了一个mbuf, 这个mbuf就是送给协议栈处理的mbuf.
bus_dma_tag_t htag;
bus_dma_tag_t ptag;u32 bytes; /* Used for AIM calc */
u32 packets;
};
struct ixgbe_tx_buf {
u32 eop_index;
struct mbuf *m_head;
bus_dmamap_t map;
};
struct ixgbe_rx_buf {
struct mbuf *m_head;
struct mbuf *m_pack;
struct mbuf *fmp;
bus_dmamap_t hmap;
bus_dmamap_t pmap;
};
struct adapter {
/*
** Queues:
** This is the irq holder, it has 网卡有多少个队列就有多少个该结构, 每个队列是与IRQ一对一的,且这里说的 RX/TX pair 是指针, 指向的是在rx_rings/tx_rings 分配的内容的
** and RX/TX pair or rings associated
** with it.
*/
struct ix_queue *queues; ===============>假设16个队列的IXGBE来说就是分配16个该结构
/*
* Transmit rings:
* Allocated at run time, an array of rings.
*/
struct tx_ring *tx_rings; ===============>假设16个队列的IXGBE来说就是分配16个该结构
int num_tx_desc;
/*
* Receive rings:
* Allocated at run time, an array of rings.
*/
struct rx_ring *rx_rings; ===============>假设16个队列的IXGBE来说就是分配16个该结构
}
struct ix_queue {
struct adapter adapter;
u32 msix; / This queue’s MSIX vector /
u32 eims; / This queue’s EIMS bit */
u32 eitr_setting;
u32 stress_ticks;
struct resource *res;
void *tag;
struct tx_ring *txr; /一个队列结构上挂着两个方向的ring/ ==========>用adaptor里面的 tx_rings 来初始化这里的txr
struct rx_ring *rxr;/这个指针将在ixgbe_allocate_queues中赋值成在此函数中malloc出来的adapter->rx/tx_rings/
struct task que_task;
struct taskqueue *tq;
u64 irqs;
u64 stress_out;
};
/无论igb和ixgbe用多少个队列,一块物理的网卡只有一个adapter,起多队列的特性都是包含在adapter中的/
ixgbe_allocate_queues(){
malloc出来num_queues个ix_queue队列==>adapter->queues = malloc();
…tx_rings==>adapter->tx_rings = malloc(*num_queues);
…rx_rings==>adapter->rx_rings = malloc(*num_queues);
/*对每个(共num_queues个,每个队列上都有rx/tx_ring,其实就相当于多个队列的em(em是FreeBSD下1G网卡的驱动命名主要的网卡类型是8254x, 82571/2/4等)网卡实现)tx/rx_ring 根据*/
for (i = 0; i < adapter->num_queues; i++) {
que = &adapter->queues[i];
que->adapter = adapter;
que->txr = &adapter->tx_rings[i];
que->rxr = &adapter->rx_rings[i];
}
}
以上相关结构关联图: