2.4高性能网络设计专栏-基于dpdk的用户态协议栈的实现
a. dpdk的环境搭建
1. 配置多队列网卡
使用cat /proc/interrupts | grep ens160可查看网卡ens160情况, 如果显式的行数只有1需要修改配置,编辑Vmware虚拟机的配置文件,以.vmx为后缀,添加这两行:


小问题
配置网卡的这时候我遇到了个小问题,最后解决了,总结一下路程:
我想给我的ubuntu虚拟机新添一个网卡ens33,然后ens33专门负责跟主机ssh连接,然后ens160专门处理多队列网卡。于是我在虚拟机设置里专门为其分配了一块ens33网卡。

但是重启后,发现主机无法ping通,然后折腾了半天。
输入ifconfig & ip a发现我的两块网卡的状态是'down':

上网搜索后发现可以使用下面的命令临时解决:
sudo ip link set ens33 up
sudo dhclient ens33
sudo systemctl restart NetworkManager
此时就主机就可以正常连接和ping通这台虚拟机了,但是这种方法治标不治本,下次重启虚拟机网卡还是不工作。
我们需要借助下面的方法来解决问题。
方法就是停止并禁用桌面版的 NetworkManager, 改用服务器级网络服务 networkd 来管理。
# 停止并禁用 NetworkManager
sudo systemctl stop NetworkManager
sudo systemctl disable NetworkManager
# 启用服务器级网络服务
sudo systemctl enable systemd-networkd
sudo systemctl start systemd-networkd
# Netplan 配置, 建议在root用户下进行
sudo vim /etc/netplan/01-server-config.yaml
仿照下面的内容修改
network:
version: 2
renderer: networkd # 核心修改:切换到底层服务,不再依赖图形界面
ethernets:
# 管理网卡 (ens33)
# 对应 VMX 中的 ethernet0 (Slot 33)
ens33:
dhcp4: true
dhcp4-overrides:
route-metric: 100
ens160:
dhcp4: true
dhcp4-overrides:
use-routes: false # 关键:不抢网关,保证 SSH 稳定
route-metric: 200
# 修正权限
sudo chmod 600 /etc/netplan/01-server-config.yaml
sudo netplan apply
sudo reboot
另一个解决方法
sudo vim /etc/network/interfaces
按照下面的配置,也就是ens33(桥接模式作为ssh连接的机器,负责联通主机),ens160作为DPDK网卡配置

# interfaces(5) file used by ifup(8) and ifdown(8)
auto lo
iface lo inet loopback
# NAT
auto ens33
iface ens33 inet dhcp
# DODK
auto ens160
iface ens160 inet manual
up ip link set ens160 up
down ip link set ens160 down

然后reboot重启也可以解决
2. hugepage, 大页/巨页
页(page)是虚拟内存中固定大小的块。操作系统将进程的虚拟地址空间划分为多个页,每个页的大小通常是 4 KB
DPDK需要使用到大页内存,在高并发海量大数据包的场景下,常规的4KB内存页面无法有效承载的,所有我们需要配置大页为2M或者1G,大大降低同等内存条件下的页表项,进而减少页表查询和缺页中断。
sudo vim /etc/default/grub
给GRUB_CMDLINE_LINUX追加这三个配置, "default_hugepagesz=1G hugepagesz=1G hugepages=1024"

# 更新
sudo update-grub
# 重启虚拟机
下载并且配置DPDK编译环境
ubuntu22.04安装dpdk22.07
参考安装地址
下载网站:https://core.dpdk.org/download/ ,由于我的ubuntu是22.04版本,这里选择dpdk 22.07版本。
(我也尝试使用dpdk-19.08.02版本了,但编译时,内核GCC版本不适配,所以选择dpdk 22.07, 可以看下文有ubuntu16.04安装dpdk19.08)
wget https://fast.dpdk.org/rel/dpdk-22.07.tar.xz
# 解压到虚拟机的`/dpdk-22.07`目录下。
tar xf dpdk-22.07.tar.xz
# 配置DPDK编译环境
# 安装编译所需要的环境库
sudo apt-get update
sudo apt-get install gcc
sudo apt-get install build-essential
sudo apt-get install libnuma-dev
sudo apt-get install pkg-config
sudo apt-get install meson
sudo apt install python3-pyelftools
# 编译dpdk
cd dpdk-22.07
# meson build这一步需要很长时间,可以修改一下配置文件,裁剪编译更快
meson build
cd build
ninja
ninja install
执行完之后所有的库都安装在 /usr/local/lib/x86_64-linux-gnu/ 目录。
可执行程序和脚本都安装在 /usr/local/bin/ 目录。
要卸载只需执行 ninja uninstall 即可。
裁剪编译
默认编译时,会默认编译不需要的驱动,导致编译很慢。在虚拟机中,很多驱动都可以不需要,因此可以做裁剪。
具体在执行 meson build 之前,
修改 drivers/meson.build 文件,subdirs 里只保留 ‘bus’,‘mempool’,‘net’ 即可。
修改 drivers/bus/meson.build 文件,drivers 里只保留 ‘pci’,‘vdev’ 即可。
修改 drivers/mempool/meson.build 文件,drivers 里只保留 ‘ring’,‘stack’ 即可。
修改 drivers/net/meson.build 文件,drivers 里只保留 ‘e1000’ 即可【因为虚拟机网卡使用的是 e1000 驱动】。
接着执行 meson build。
编译 igb uio 驱动
git clone http://dpdk.org/git/dpdk-kmods
cd dpdk-kmods/linux/igb_uio
make
# 编译出来 igb_uio.ko
验证环境
cd examples/l2fwd
make

加载 igb uio 驱动
cd dpdk-kmods/linux/igb_uio
modprobe uio
insmod igb_uio.ko intr_mode=legacy
分配巨页
sudo vim /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages
# 在文件里把默认的0修改为512,退出保存
绑定网卡
ifconfig ens160 down
dpdk-devbind.py -b igb_uio ens160
验证
cd /dpdk-22.07/examples/l2fwd/build/
./l2fwd -l 0-1 -- -p 0x1 -T 1

解绑网卡
如果之后想把刚刚绑定的网卡解绑,需要通过下面的方法:
# 获取网卡设备号
lspci | grep Eth

我的ens160应该是最后一个 03:00.0
dpdk-devbind.py -u 03:00.0
dpdk-devbind.py -b e1000 03:00.0
ifconfig ens160 up
ubuntu16.04安装dpdk19.08
参考网站
下载源码
wget https://fast.dpdk.org/rel/dpdk-19.08.2.tar.xz
tar xf dpdk-19.08.2.tar.xz
设置dpdk环境变量

export RTE_SDK=/home/chan/dpdk-stable-19.08.2 # 指向DPDK的源代码目录
export RTE_TARGET=x86_64-native-linux-gcc # 指向DPDK的编译输出目录
配置dpdk编译环境
安装必要包
sudo apt-get update
sudo apt-get install gcc
sudo apt-get install build-essential
sudo apt-get install libnuma-dev
sudo apt-get install pkg-config
运行dpdk-setup
#切换到root用户
su
cd /home/chan/dpdk-stable-19.08.2
./usertools/dpdk-setup.sh
-
选择39进行编译 (这一步时间比较长 20分钟+)

编译完会多一个文件夹

-
选择 43 插入 IGB_UIO 模块, 选择网卡为 vmxnet3 会加载此模块。

-
选择 44 插入 VFIO 模块,安全硬件虚拟化,确保设备只能访问限定内存区域避免程序错误导致系统崩溃。

-
选择 45 绑定 KNI 模块内核协议栈桥接,做到DPDK仅从硬件收发数据,将数据交由内核无需重构整个网络栈。

-
选择 46 ,47配置大页,针对两种不同系统(非NUMA/NUMA),配置巨页页数,将指定大小的巨页都分为512页。


-
选择 49 绑定 IGB UIO模块(在这里需要将ens160网卡down掉)。
ifconfig ens160 down
然后在setup中 输入49,物理设备号输入 ens160的设备号


选择 60 退出
DPDK编译环境就已经完成~
测试dpdk环境
cd /home/chan/dpdk-stable-19.08.2/examples/helloworld
make
./build/helloworld

网卡的作用
b. 使用dpdk收数据

- 网卡:核心作用是让计算机能够接入网络,实现数据的发送与接收,是计算机与网络之间的桥梁。
负责AD转换 [接收数据:电信号(高低电平)\(\rightarrow\)数字信号]、DA转换 [发送数据:数字信号\(\rightarrow\)电信号]。 - 网卡驱动:使得网卡正常工作,Linux内核官方维护,了解即可。主要提供了两层:1)NIC负责把原始数据放至相应位置(sk_buff),提供给网络层的TCP/IP协议栈。
- TCP/IP:
网卡的作用:网络通信中,大量的sk_buff选择什么数据结构保存?
UIO: 截获PCI的地址
PCI
1.dpdk能不能提升Redis qps?
不能,dpdk不一定能提升
2.dpdk能不能减少Nginx延迟?
不明显
3.dpdk能不能提升吞吐量?
可以, 主要是来提升吞吐量的
dpdk的主要作用是把网卡数据截获,能够抓取到原始数据,做自己的协议栈、posixapi、应用,以提升性能, 特别适合高性能网络开发
dpdk的应用场景:
- 数据备份(适用于传输大文件,底层用DPDK,应用层用RDMA)
- 网关防火墙
dpdk用户协议栈: - a。ntytcp
- b. 4.4BSD (腾讯的f-stack协议栈用的BSD,自己写的Posix api,使其适配dpdk)
- c. mtcp
- d.lwip
- e.vapp
开发 -> 编译 -> 运行
编译的时候我们需要借助Makefile文件(可以复制/dpdk-22.07/examples/helloworld/Makefile)
mkdir /dpdk-22.07/dpdk
cp /dpdk-22.07/examples/helloworld/Makefile /dpdk-22.07/dpdk
然后编写一份代码ustack.c
#include <stdio.h>
#include <rte_eal.h>
int main(int argc, char *argv[]){
if(rte_eal_init(argc, argv) < 0) {
rte_exit(EXIT_FAILURE, "Error with init\n");
}
printf("Hello World!\n");
return 0;
}
修改Makefile

cd /dpdk-22.07/dpdk
make
./build/ustack

至此,我们已经完成了dpdk收到数据的前提条件:dpdk绑定网卡

dpdk mbuf 与 kernel sk_buff 它们的作用是一样的
参考:
https://bbs.csdn.net/topics/620040250
https://blog.csdn.net/qq_57951250/article/details/155463935?spm=1001.2014.3001.5502

浙公网安备 33010602011771号