1. 前言
    网卡驱动里,CPU和MAC控制器都需要对DMA描述符空间进行读取或者写入。DMA描述符空间又会采用到CACHE和零拷贝技术,以往都是驱动自己去申请、关联内存和刷新(flush和invalidate)CACHE。
    描述符助手则是把这些工作在内核里完成,对驱动提供接口即可,此文就对这些接口功能做一些分析。
  2. 创建
    实现发送静态内存空间申请、发送零拷贝内存创建(但不申请空间)、接收静态内存空间申请、接收零拷贝内存空间申请,及CACHE刷新。函数原型及入参如程序清单 2.1:
    程序清单 2.1
    / create descriptor helper /
    struct netdev_desc_helper
    netdev_desc_helper_create (size_t each_buf_size, /
    每帧大小 /
    size_t pad_size, /
    PAD /
    int cache_ts_en, /
    发送静态内存cache刷新使能 /
    int cache_rs_en, /
    接收静态内存cache刷新使能 /
    int cache_zc_en, /
    接收零拷贝内存cache刷新使能 /
    int tx_buf_cnt, /
    发送描述符数 /
    int rx_buf_cnt, /
    接收描述符数 /
    int tx_zc_en, /
    发送零拷贝使能 /
    int rx_zc_cnt) /
    接收零拷贝池数 */
    可知,接收零拷贝是默认使能的,且零拷贝池数是接收描述符数的2倍即申请2倍空间(下文会对此分析)。创建流程如图 2.1:
    网卡驱动描述符助手功能浅析_第1张图片
    图 2.1 描述符助手创建
    这里需要关注的是,零拷贝池的每个节点大小是帧大小加上节点头大小,帧对应pbuf空间,而实际数据的存储则又是pbuf里的payload空间。关系如图 2.2:
    网卡驱动描述符助手功能浅析_第2张图片
    图 2.2 零拷贝池节点结构
  3. 发送
    发送需要关注两个函数,发送前prepare即将上层要发送的pbuf->payload关联到发送描述符,发送后clean即是把该pbuf空间释放掉。如图 3.1:
    网卡驱动描述符助手功能浅析_第3张图片
    图 3.1 发送流程
  4. 接收
    接收同样是关注两个函数,接收前input取出内容,接收后refill重关联描述符与零拷贝池。但多一个流程,初始化时先把零拷贝地址池关联到接收描述符并写入MAC控制器。如图 4.1:
    网卡驱动描述符助手功能浅析_第4张图片
    图 4.1 接收流程
    这里对为什么接收零拷贝池申请2倍内存做一个推测,由于其他空间是用完后即可再次利用,而接收描述符空间是要等上层归还到零拷贝池链表后,当上层归还不及时时,零拷贝池数量实际就没申请的那么多,所以直接采取极端情形即申请2倍。