从互不相识的两块网卡到l2fwd相连


这周末在单服务器上做了一个dpdk互联实验,在此记录一下其中过程:


1. 知道线插在哪块网卡上

服务器是Dell r730,有不少pci插槽。本人手中的这台机器插上了4块Intel XL710 40Gb网卡,虽然机器背部有标号,但似乎与pci地址并不成对应关系,所以就算把网线插进去之后也完全不知道对应的是哪块网卡的哪个端口。

而Linux其实可以方便地查看各个设备的物理状态,使用如下命令:

$ ls /sys/class/net

得到输出:

eno1  eno2  eno3  eno4  enp130s0f0  enp130s0f1  enp4s0f0  enp4s0f1  enp5s0f0  enp5s0f1  enp6s0f0  enp6s0f1  lo  virbr0  virbr0-nic

可以发现各个物理网口都对应了一个目录,此目录下的carrier提示了此网口是否插入了线缆:

$ cat /sys/class/net/enp4s0f0/carrier
0

$ cat /sys/class/net/enp4s0f1/carrier
1

$ cat /sys/class/net/enp6s0f0/carrier
cat: /sys/class/net/enp6s0f0/carrier: Invalid argument

其中,0,1表示此网口未插入或插入了线缆。而如果此网口的状态为down,则提示invalid argument,执行ifconfig up即可。

各网口的operstate提示了其是否正常工作:

$ cat /sys/class/net/enp4s0f1/operstate
up

$ cat /sys/class/net/enp4s0f0/operstate
down

$ cat /sys/class/net/enp6s0f0/operstate
down

无论某个网口是否属于up的状态,只要它没有正常工作,此处显示的状态就是down,反之为up。

至此,笔者确定了线缆两端分别为enp4s0f1与enp5s0f1。

注意,如果使用不合规的线缆,在插入网口时会提示以下错误:

[timestamp] i40e 0000:04:00.0: Rx/Tx is disabled on this device because an unsupported SFP module type was detected.
[timestamp] i40e 0000:04:00.0: Refer to the Intel(R) Ethernet Adapters and Devices User Guide for a list of supported modules.

笔者造成这个错误的原因是使用了10G的光缆。在换用支持40G的铜缆之后,插入网口不再提示错误。

2. 将网卡与dpdk绑定

dpdk在绝大多数时候都要求自身对资源与设备处于独占的状态,最典型的例子就是大页内存。用户只有挂上hugepage之后才能正常使用dpdk应用,这一过程是直接在物理内存中预留了一片空间,不允许内核进行使用,而由dpdk应用专用,保证了其对资源的独占。

类似的,dpdk在使用网卡时,也需要提前保证其对网卡的独占。这个过程可以通过dpdk提供的devbind脚本来实现:

$ cd dpdk-21.05/
$ ./usertools/dpdk-devbind.py --status


Network devices using DPDK-compatible driver
============================================

Network devices using kernel driver
===================================
0000:01:00.0 'NetXtreme BCM5720 2-port Gigabit Ethernet PCIe 165f' if=eno1 drv=tg3 unused=vfio-pci *Active*
0000:01:00.1 'NetXtreme BCM5720 2-port Gigabit Ethernet PCIe 165f' if=eno2 drv=tg3 unused=vfio-pci 
0000:02:00.0 'NetXtreme BCM5720 2-port Gigabit Ethernet PCIe 165f' if=eno3 drv=tg3 unused=vfio-pci 
0000:02:00.1 'NetXtreme BCM5720 2-port Gigabit Ethernet PCIe 165f' if=eno4 drv=tg3 unused=vfio-pci 
0000:04:00.0 'Ethernet Controller XL710 for 40GbE QSFP+ 1583' if=enp4s0f0 drv=i40e unused=vfio-pci
0000:04:00.1 'Ethernet Controller XL710 for 40GbE QSFP+ 1583' if=enp4s0f1 drv=i40e unused=vfio-pci *Active*
0000:05:00.0 'Ethernet Controller XL710 for 40GbE QSFP+ 1583' if=enp5s0f0 drv=i40e unused=vfio-pci 
0000:05:00.1 'Ethernet Controller XL710 for 40GbE QSFP+ 1583' if=enp5s0f1 drv=i40e unused=vfio-pci *Active*
0000:06:00.0 'Ethernet Controller XL710 for 40GbE QSFP+ 1583' if=enp6s0f0 drv=i40e unused=vfio-pci 
0000:06:00.1 'Ethernet Controller XL710 for 40GbE QSFP+ 1583' if=enp6s0f1 drv=i40e unused=vfio-pci 
0000:82:00.0 'Ethernet Controller XL710 for 40GbE QSFP+ 1583' if=enp130s0f0 drv=i40e unused=vfio-pci 
0000:82:00.1 'Ethernet Controller XL710 for 40GbE QSFP+ 1583' if=enp130s0f1 drv=i40e unused=vfio-pci

...

可以发现,笔者刚才up的两个网口处于active状态。使用如下命令将网卡与dpdk提供的驱动绑定:

$ sudo ./usertools/dpdk-devbind.py --bind=vfio-pci enp4s0f1
Routing table indicates that interface 0000:00:04.0 is active. Not modifying

则会提示上述错误。

出现此错误的原因是,dpdk不能保证内核没有在使用此网口,因此不能直接将其抢夺过来。使用sudo ifconfig enp4s0f1 down将此网口down之后,上述命令可以正常执行。

将两个网口都与dpdk提供的vfio驱动绑定后,再次查看状态:

$ ./dpdk-21.05/usertools/dpdk-devbind.py -s


Network devices using DPDK-compatible driver
============================================
0000:04:00.1 'Ethernet Controller XL710 for 40GbE QSFP+ 1583' drv=vfio-pci unused=i40e
0000:05:00.1 'Ethernet Controller XL710 for 40GbE QSFP+ 1583' drv=vfio-pci unused=i40e

Network devices using kernel driver
===================================
0000:01:00.0 'NetXtreme BCM5720 2-port Gigabit Ethernet PCIe 165f' if=eno1 drv=tg3 unused=vfio-pci *Active*
0000:01:00.1 'NetXtreme BCM5720 2-port Gigabit Ethernet PCIe 165f' if=eno2 drv=tg3 unused=vfio-pci 
0000:02:00.0 'NetXtreme BCM5720 2-port Gigabit Ethernet PCIe 165f' if=eno3 drv=tg3 unused=vfio-pci 
0000:02:00.1 'NetXtreme BCM5720 2-port Gigabit Ethernet PCIe 165f' if=eno4 drv=tg3 unused=vfio-pci 
0000:04:00.0 'Ethernet Controller XL710 for 40GbE QSFP+ 1583' if=enp4s0f0 drv=i40e unused=vfio-pci 
0000:05:00.0 'Ethernet Controller XL710 for 40GbE QSFP+ 1583' if=enp5s0f0 drv=i40e unused=vfio-pci 
0000:06:00.0 'Ethernet Controller XL710 for 40GbE QSFP+ 1583' if=enp6s0f0 drv=i40e unused=vfio-pci 
0000:06:00.1 'Ethernet Controller XL710 for 40GbE QSFP+ 1583' if=enp6s0f1 drv=i40e unused=vfio-pci 
0000:82:00.0 'Ethernet Controller XL710 for 40GbE QSFP+ 1583' if=enp130s0f0 drv=i40e unused=vfio-pci 
0000:82:00.1 'Ethernet Controller XL710 for 40GbE QSFP+ 1583' if=enp130s0f1 drv=i40e unused=vfio-pci 

...

此时,在Linux下已经观察不到enp4s0f1enp5s0f1(使用ifconfig -a),其已由dpdk接管。

3. 单机器的两个dpdk进程互通

要保证在单机器实现两个dpdk进程的互通,就必须保证它们看到的网口、逻辑核与内存均为独立的。此处以l2fwd为例,说明应当使用的参数:

$ sudo ./build/l2fwd -c 0x2 -a 04:00.1 -- -p 0x1

$ (another terminal) sudo ./build/l2fwd --file-prefix=tmp -c 0x4 -a 05.00.1 -- -p 0x1

第一行命令中,-c 0x2指定了此进程只能看到1号核,-a 04:00.1指定了此进程只能看到指定的pci设备,此二者为EAL参数。

在“--”之后的参数为l2fwd定义的参数。其中-p指定port mask,即在所有看到的端口中,使用哪些端口。
实际上,如果不指定-a 04:00.1,此进程在启动时会占有所有绑定了vfio驱动的端口,此时-p参数就有了其存在的意义,指定为0x1则只能看到04:00.1上的设备,指定为0x3时则可以看到两个网口。

第二行命令中,还需额外指定EAL参数--file-prefix(名称无所谓)。此参数使得进程在占用大页时使用不同的文件前缀,从而与正在运行的dpdk进程相区别。

至此,可以观察到两个l2fwd之间在互相收发包,即完成了单机两网卡的dpdk互联。