dpdk-go
Golang高性能轻量级网络包收发框架
dpdk环境搭建
# 建议使用Ubuntu18.04或Ubuntu20.04
# 安装numactl
unzip numactl-master.zip
cd numactl-master
./autogen.sh
./configure
make -j 8
make install
ldconfig
# 安装dpdk-18.11.11
tar -xvf dpdk-18.11.11.tar.xz
cd dpdk-stable-18.11.11
# 环境变量
export RTE_SDK="/root/dpdk-stable-18.11.11/"
export RTE_TARGET="x86_64-native-linuxapp-gcc"
# 编译DPDK
make config T=$RTE_TARGET
make -j 8 install T=$RTE_TARGET
# 配置dpdk
# UIO和VFIO二选一
# UIO
modprobe uio
insmod /root/dpdk-stable-18.11.11/x86_64-native-linuxapp-gcc/kmod/igb_uio.ko
/root/dpdk-stable-18.11.11/usertools/dpdk-devbind.py --bind=igb_uio eth0
# VFIO Aliyun适用
# 参考链接
https://help.aliyun.com/document_detail/310880.htm
cat /proc/cmdline
vim /etc/default/grub
# "GRUB_CMDLINE_LINUX" 追加 "intel_iommu=on"
update-grub2
reboot
# 检查是否开启成功
cat /proc/cmdline
modprobe vfio && modprobe vfio-pci
echo 1 > /sys/module/vfio/parameters/enable_unsafe_noiommu_mode
ethtool -i eth0
# vfio-pci后的参数即为ethtool所查看的网卡的pcie设备号
/root/dpdk-stable-18.11.11/usertools/dpdk-devbind.py -b vfio-pci 0000:00:05.0
# KNI
insmod /root/dpdk-stable-18.11.11/x86_64-native-linuxapp-gcc/kmod/rte_kni.ko carrier=on
# 内存大页
echo 1024 > /sys/devices/system/node/node0/hugepages/hugepages-2048kB/nr_hugepages
mkdir -p /mnt/huge_2M
mount -t hugetlbfs none /mnt/huge_2M -o pagesize=2M
echo 0 > /sys/devices/system/node/node0/hugepages/hugepages-1048576kB/nr_hugepages
mkdir -p /mnt/huge_1G
mount -t hugetlbfs none /mnt/huge_1G -o pagesize=1G
如何使用
go get github.com/flswld/dpdk-go
# 确保CGO开启并添加以下环境变量
export CGO_CFLAGS_ALLOW=.*
export CGO_LDFLAGS_ALLOW=.*
使用示例
// 详见example
// DirectDpdk 直接使用dpdk收发网络报文
func DirectDpdk() {
cfg := &dpdk.Config{
GolangCpuCoreList: []int{4, 5}, // golang侧使用的核心编号列表 非单核模式下至少需要两个核心
DpdkCpuCoreList: []int{0, 1, 2, 3}, // dpdk侧使用的核心编号列表 非单核模式下至少需要四个核心
DpdkMemChanNum: 1, // dpdk内存通道数
RingBufferSize: 1024 * 1024 * 128, // 环状缓冲区大小
DebugLog: true, // 收发包调试日志
StatsLog: true, // 收发包统计日志
IdleSleep: false, // 空闲睡眠 降低cpu占用
SingleCore: false, // 单核模式 物理单核机器需要开启
KniBypassTargetIp: false, // kni旁路目标ip dpdk-go只接收来自目标ip的包 其他的包全部送到kni网卡
TargetIpAddr: "", // 目标ip地址
}
// 启动dpdk
dpdk.Run(cfg)
// 通过RX和TX管道发送接收原始以太网报文
pkt := <-dpdk.DPDK_RX_CHAN
dpdk.DPDK_TX_CHAN <- pkt
// 停止dpdk
dpdk.Exit()
}
// NetworkEngine 简易网络协议栈
func NetworkEngine() {
ec := &engine.Config{
DebugLog: true, // 调试日志
MacAddr: "00:0C:29:3E:3E:DF", // mac地址
IpAddr: "192.168.199.199", // ip地址
NetworkMask: "255.255.255.0", // 子网掩码
GatewayIpAddr: "192.168.199.1", // 网关ip地址
}
// 初始化协议栈
e, err := engine.InitEngine(ec)
if err != nil {
panic(err)
}
dc := &dpdk.Config{
GolangCpuCoreList: []int{4, 5}, // golang侧使用的核心编号列表 非单核模式下至少需要两个核心
DpdkCpuCoreList: []int{0, 1, 2, 3}, // dpdk侧使用的核心编号列表 非单核模式下至少需要四个核心
DpdkMemChanNum: 1, // dpdk内存通道数
RingBufferSize: 1024 * 1024 * 128, // 环状缓冲区大小
DebugLog: true, // 收发包调试日志
StatsLog: true, // 收发包统计日志
IdleSleep: false, // 空闲睡眠 降低cpu占用
SingleCore: false, // 单核模式 物理单核机器需要开启
KniBypassTargetIp: false, // kni旁路目标ip dpdk-go只接收来自目标ip的包 其他的包全部送到kni网卡
TargetIpAddr: "", // 目标ip地址
}
// 启动协议栈
e.RunEngine(dc)
// kcp协议栈测试
KcpServer()
time.Sleep(time.Second)
KcpClient()
time.Sleep(time.Minute)
// 停止协议栈
e.StopEngine()
}