DPDK踩坑记
Posted yuanyun_elber
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了DPDK踩坑记相关的知识,希望对你有一定的参考价值。
公司的新产品是一款服务器端的网卡芯片,支持各种密码学计算offload,是清华大学的可重构结构,还挺牛逼的,不过再怎么牛逼,这还是一块网卡芯片,上网是主要的功能,所以最近入坑DPDK了。之所以说入坑,是因为网络方面完全是小白,学习的过程就是不断填坑的过程。dpdp网上的资料已经挺多的了,我主要把自己学习过程中遇到的问题记录下来,如果觉得很小儿科的大神可以飘过了......
硬件环境: (主机Intel(R) Core(TM) i5-4590 CPU @ 3.30GHz + 我司的n10芯片网卡)* 2, 一套作为待测机,一套作为陪测机,我们的网卡是一个四口版本,也就是可以ifconfig会显示出4张网卡,暂时我们只连接了其中的一路,即陪测机的port3 连接到待测机的port2。
操作系统: centos,Linux localhost.localdomain 3.10.0-1160.el7.x86_64
dpdk版本: 20.02
dpdk pktgen版本:20.02.0
N10的DPDK补丁目前还不支持meson编译,只能make编译,所以dpdk版本只能20.11之前的,20.11之后都是meson编译的,我们选择了20.02版本
wget http://fast.dpdk.org/rel/dpdk-20.02.1.tar.xz
xz -d dpdk-20.02.1.tar.xz
tar -xf dpdk-20.02.1.tar
cd dpdk-stable-20.02.1
export RTE_SDK=`pwd` ##系统临时环境变量,ssh断开重连后需要重新输入此命令
git apply ../tsrn10-pmd/20.02/0001-net-tsrn10-add-PMD-skeleton.patch
make -j 8 install T=x86_64-native-linuxapp-gcc CONFIG_RTE_EAL_IGB_UIO=y
如果编译提示numa.h找不到的话
yum install numactl-devel
绑定网卡
devbind.py -b igb_uio 01:00.1
然后再跑一下testpmd,提示
Cause: Creation of mbuf pool for socket 0 failed: Invalid argument
echo 2048 > /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages
就可以运行了
接下来在陪测机安装pktgen用来发包,注意版本和dpdk适配
wget http://git.dpdk.org/apps/pktgen-dpdk/snapshot/pktgen-dpdk-pktgen-20.02.0.tar.gz
tar xvf pktgen-dpdk-pktgen-20.02.0.tar.gz
cd pktgen-dpdk-pktgen-20.02.0
export RTE_SDK=/bak/dpdk-stable-20.02.1/
export RTE_TARGET=x86_64-native-linuxapp-gcc
make
make install
提示缺少lua.h,在3.5以上的pktgen-dpdk编译时,lua的版本必须要在5.3以上。而centos7yum源中自带的lua包只支持到5.1
使用源码包编译安装:
lua官网下载地址:https://www.lua.org/ftp/
tar -xvf #解压lua
cd lua-5.4.3
make linux #编译链接库
make install #安装到系统中同时修改系统环境变量
make local #使当前用户
提示
fatal error: pcap/pcap.h: No such file or directory
安装lipcap库:
yum install libpcap-devel
接下来陪测机和待测机分别设置好hugepage,加载igb_uio.ko后,使用dpdk-devbind.py进行网卡绑定就可以跑testpmd和pktgen了。
mkdir -p /dev/hugepages
mountpoint -q /dev/hugepages || mount -t hugetlbfs nodev /dev/hugepages
echo 2048 > /sys/devices/system/node/node0/hugepages/hugepages-2048kB/nr_hugepages
modprobe uio
insmod ../dpdk-stable-20.02.1/x86_64-native-linuxapp-gcc/build/kernel/linux/igb_uio/igb_uio.ko
ifconfig enp1s1f1 down
../dpdk-stable-20.02.1/usertools/dpdk-devbind.py -b igb_uio 01:00.0
../dpdk-stable-20.02.1/usertools/dpdk-devbind.py -b igb_uio 01:00.1
#./app/x86_64-native-linuxapp-gcc/pktgen -l 0-3 -n 1 -- -P -m "[1].3" #陪测机端跑这条,发包
# ../dpdk-stable-20.02.1/x86_64-native-linuxapp-gcc/app/testpmd -l 0-3 -n 4 -- -i #待测机端跑这条,收包
试试看,好像有点不对,陪测机的pktgen端可以看到发包数如下
而待测机的testpmd端显示rx-packets是0
testpmd> show port stats 2
######################## NIC statistics for port 2 ########################
RX-packets: 0 RX-missed: 0 RX-bytes: 0
RX-errors: 0
RX-nombuf: 0
TX-packets: 0 TX-errors: 0 TX-bytes: 0
Throughput (since last show)
Rx-pps: 0 Rx-bps: 0
Tx-pps: 0 Tx-bps: 0
############################################################################
但是用show port xstats 2看是有收到包的,数字也对得上
testpmd> show port xstats 2
###### NIC extended statistics for port 2
rx_good_packets: 0
tx_good_packets: 0
rx_good_bytes: 0
tx_good_bytes: 0
rx_missed_errors: 0
rx_errors: 0
tx_errors: 0
rx_mbuf_allocation_errors: 0
rx_q0packets: 0
rx_q0bytes: 0
rx_q0errors: 0
tx_q0packets: 0
tx_q0bytes: 0
Mac Local Fault: 0
Mac remote Fault: 0
Rx good bad Pkts: 103731328
Rx good bad bytes: 6638804992
Rx good Pkts: 103731328
RX good Bytes: 6638804992
Rx Broadcast Pkts: 0
Rx Multicast Pkts: 0
Rx Crc Frames Err Pkts: 0
Rx len Err with Crc err: 0
Rx jabber Error : 0
Rx len Err Without Other Error: 0
Rx Len Shorter 64Bytes Without Err: 0
Rx Len Oversize Max Support Err: 0
Rx 64Bytes Frame Num: 103731328
Rx 65Bytes To 127Bytes Frame Num: 0
Rx 128Bytes To 255Bytes Frame Num: 0
代码中看上去应该是如下函数响应show port stats命令的
static void tsrn10_stats_get(struct rte_eth_dev *dev,
struct rte_eth_stats *stats)
#endif
struct tsrn10_eth_port *port = TSRN10_DEV_TO_PORT(dev);
struct tsrn10_hw *hw = TSRN10_DEV_TO_HW(dev);
struct rte_eth_dev_data *data = dev->data;
uint64_t rx_miss = 0;
int i = 0;
PMD_INIT_FUNC_TRACE();
memset(stats, 0, sizeof(*stats));
tsrn10_get_hw_stats(dev);
for (i = 0; i < data->nb_rx_queues; i++)
stats->q_ipackets[i] = ((struct tsrn10_rx_queue **)
(data->rx_queues))[i]->stats.ipackets;
stats->q_ibytes[i] = ((struct tsrn10_rx_queue **)
(data->rx_queues))[i]->stats.ibytes;
stats->ipackets += stats->q_ipackets[i];//ipackets应该就是收包数
stats->ibytes += stats->q_ibytes[i];
调试一下,的确这个值是0
这是怎么回事呢,翻翻代码,看看其他网卡是怎么更新这个值的:
static int
ixgbe_dev_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
struct ixgbe_hw *hw =
IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
struct ixgbe_hw_stats *hw_stats =
IXGBE_DEV_PRIVATE_TO_STATS(dev->data->dev_private);
struct ixgbe_macsec_stats *macsec_stats =
IXGBE_DEV_PRIVATE_TO_MACSEC_STATS(
dev->data->dev_private);
uint64_t total_missed_rx, total_qbrc, total_qprc, total_qprdc;
unsigned i;
total_missed_rx = 0;
total_qbrc = 0;
total_qprc = 0;
total_qprdc = 0;
ixgbe_read_stats_registers(hw, hw_stats, macsec_stats, &total_missed_rx,
&total_qbrc, &total_qprc, &total_qprdc);
//来源是这个hw_stats,而hw_stats是从硬件寄存器读取的
if (stats == NULL)
return -EINVAL;
/* Fill out the rte_eth_stats statistics structure */
stats->ipackets = total_qprc;
stats->ibytes = total_qbrc;
stats->opackets = hw_stats->gptc;
stats->obytes = hw_stats->gotc;
for (i = 0; i < IXGBE_QUEUE_STAT_COUNTERS; i++)
stats->q_ipackets[i] = hw_stats->qprc[i];
stats->q_opackets[i] = hw_stats->qptc[i];
stats->q_ibytes[i] = hw_stats->qbrc[i];
stats->q_obytes[i] = hw_stats->qbtc[i];
stats->q_errors[i] = hw_stats->qprdc[i];
ixgbe_read_stats_registers是从硬件去去读寄存器更新这个值。
找了很多网卡,都是这种从硬件读取的方式,类似的,我们也有硬件寄存器记录一些信息,在tsrn10_get_hw_stats这个函数中会去读取:
tsrn10_get_mmc_info(hw, p_id, stats, ptr);
在执行show port xstats all命令的时候就是得到这些信息
这里面的rx_good_pkts,rx_all_pkts 都有,但是没有区分队列的pkt统计
找到一个avp_ethdev.c和我们类似也是软件更新的
avp_dev_stats_get(struct rte_eth_dev *eth_dev, struct rte_eth_stats *stats)
struct avp_dev *avp = AVP_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private);
unsigned int i;
for (i = 0; i < avp->num_rx_queues; i++)
struct avp_queue *rxq = avp->dev_data->rx_queues[i];
if (rxq)
stats->ipackets += rxq->packets;
stats->ibytes += rxq->bytes;
stats->ierrors += rxq->errors;
stats->q_ipackets[i] += rxq->packets;
stats->q_ibytes[i] += rxq->bytes;
stats->q_errors[i] += rxq->errors;
for (i = 0; i < avp->num_tx_queues; i++)
struct avp_queue *txq = avp->dev_data->tx_queues[i];
if (txq)
stats->opackets += txq->packets;
stats->obytes += txq->bytes;
stats->oerrors += txq->errors;
stats->q_opackets[i] += txq->packets;
stats->q_obytes[i] += txq->bytes;
return 0;
在avp_recv_pkts中会去增加
rxq->packets += count;
而在我们的tsrn10_recv_pkts函数中
tsrn10_clean_rx_ring也会调用
rxq->stats.ipackets += nb_rx;
加断点调试一下,发现居然没有进入tsrn10_recv_pkts函数,再往前追溯rte_eth_rx_burst 也么有调用
原来问题在这个地方,testpmd命令后输入start后,终于进入了rte_eth_rx_burst ,单步的话进入回调是tsrn10_rx_burst_simple
-->tsrn10_recv_pkts-->tsrn10_clean_rx_ring,但是在下面代码的位置提前返回了,没有执行到下面更新ipackets的地方
static inline int tsrn10_clean_rx_ring(struct tsrn10_rx_queue *rxq)
struct tsrn10_rxsw_entry *rx_swbd;
uint32_t state_cmd[CACHE_FETCH_RX];
uint32_t pkt_len[CACHE_FETCH_RX] = 0;
volatile struct tsrn10_rx_desc *rxbd;
struct rte_mbuf *nmb;
int nb_dd, nb_rx = 0;
uint32_t status;
int i, j;
rxbd = &rxq->rx_bdr[rxq->next_to_clean];
status = rxbd->wb.vlan_cmd;
if (!(status & rte_cpu_to_le_32(TSRN10_CMD_DD)))
return 0;
这个应该就是PMD(poll mode)的含义了,轮询的情况下很多时候是没有收到包的,另外加断点
(gdb) b tsrn10_rxtx.c:1453
重新start一下之后,停在了断点,证明我们的直觉是正确的。
不过丢包率似乎有点高,做一组实验对比一下:
在pktgen端,默认64字节包长,设置
Pktgen:/> set 3 rate 10
设置10%的发包率,因为我们是10G的网口,差不多1Gbit/s,统计如下
######################## NIC statistics for port 2 ########################
RX-packets: 539040 RX-missed: 460960 RX-bytes: 32342400
RX-errors: 0
RX-nombuf: 0
TX-packets: 0 TX-errors: 0 TX-bytes: 0
Throughput (since last show)
Rx-pps: 27689 Rx-bps: 13291088
Tx-pps: 0 Tx-bps: 0
############################################################################
丢包率很高
如果在pktgen端设置1500字节包长,即使发包率是100%,丢包率也大大下降了
######################## NIC statistics for port 2 ########################
RX-packets: 971248 RX-missed: 5466 RX-bytes: 1452987008
RX-errors: 0
RX-nombuf: 0
TX-packets: 0 TX-errors: 0 TX-bytes: 0
Throughput (since last show)
Rx-pps: 127232 Rx-bps: 1522720256
Tx-pps: 0 Tx-bps: 0
############################################################################
符合预期
以上是关于DPDK踩坑记的主要内容,如果未能解决你的问题,请参考以下文章