DPDK全称为Date planedevelopment kit,是一个用来进行包数据处理加速的软件库。与传统的数据包处理相比,DPDK具有以下特点:
1) 轮询:在包处理时避免中断上下文切换的开销,
2) 用户态驱动:规避不必要的内存拷贝和系统调用,便于快速迭代优化
3) 亲和性与独占:特定任务可以被指定只在某个核上工作,避免线程在不同核间频繁切换,保证更多的cache命中
4) 降低访存开销:利用内存大页HUGEPAGE降低TLB miss,利用内存多通道交错访问提高内存访问有效带宽
5) 软件调优:cache行对齐,预取数据,多元数据批量操作
DPDK架构
DPDK收发包相关
一台服务器可能有多个网卡,接入到PCIe通道,每个网卡可能有一个或多个物理网口,即port,这些网口共用网卡的处理芯片。对于Intel E810 100Gbps网卡为例,单个port的接收和发送速率为100Gbps,但是两个网卡的速率最多为160Gbps左右。一个port可以有多个接收/发送队列,例如 E810 100Gbps网卡,一个port最多可以支持256个接收队列,当网卡接收到数据包时会将数据包按照RSS负载均衡算法分配给这些队列,不同的线程可以从这些队列中获取数据并处理,这样的目的是可以充分发挥多核CPU的性能。一个接收/发送队列可以设置一定数量的队列描述符,用于存放数据包的metadata。例如,E810 100Gbps网卡,最多支持4096个Rx描述符,即可以同时允许4096个数据包在网卡中等待应用程序处理,如果此时还有新的数据包到达网口,这些数据包只能被drop,就是丢包的意思。描述符中存放的是数据包在内存中的地址,而不是数据包本身。
以DPDK收包为例,首先会调用rte_pktmbuf_pool_create函数为不同的port创建内存池,内存池中可以存放mbuf对象,即数据包对象,
struct rte_mempool *mbuf_pool = rte_pktmbuf_pool_create(
strbuf, NUM_MBUFS_DEFAULT, MBUF_CACHE_SIZE, 0, RTE_MBUF_DEFAULT_BUF_SIZE, socket_id);
然后调用rte_eth_dev_configure设置队列数量,
ret_val = rte_eth_dev_configure(port_id, rx_queues, 0, &port_conf);
接着设置每个队列的描述符数量以及关联mbuf_pool,
for (uint16_t i = 0; i < rx_queues; i++) {
ret_val = rte_eth_rx_queue_setup(port_id, i, rx_descs, rte_eth_dev_socket_id(port_id), NULL,
mbuf_pool);
if (ret_val) {
RTE_LOG(ERR, NTR,
"Failed to configure descriptors for port %d with rx queue %d, error: %s\n",
port_id, i, rte_strerror(-ret_val));
return ret_val;
}
}
最后启动port,
ret_val = rte_eth_dev_start(port_id);
启动port后,可以调用rte_eth_rx_burst来轮询(PMD)获取一定数量的数据包,
rx_pkt_nb = rte_eth_rx_burst(config->port, config->queue, bufs, WORKER_RTE_MBUF_SIZE);
数据包以这个结构struct rte_mbuf *bufs[WORKER_RTE_MBUF_SIZE];来存放。
处理完数据包以后,调用函数rte_pktmbuf_free_bulk来释放相关资源,应该包含清空rx queue中的描述符,清空mbuf_pool中的数据等,
rte_pktmbuf_free_bulk(bufs, rx_pkt_nb);
参考:
wangxiaohui2015/dpdk_engineer_manual