DPDK入门(环境搭建以及小demo)
文章目录
- 零、从`0`开始配置`dpdk`环境的虚拟机
- 一、`dpdk`的编译`usertool/dpdk-setup.sh`
- 二、`dpdk`需要什么配置来支持
- 1.多队列网卡
- 2.巨页
- 三、解析接收网络数据的过程经历了什么
- 1.物理网卡
- 2.`NIC`
- 3.内核协议栈
- 4.标准接口层`Posix API`
- 5. 应用层
- 上述过程发生的拷贝
- 四、`DPDK`介绍
- 基于上述接收网络数据流程`dpdk`做的事
- `dpdk`如何组织映射的数据
- `Huge Page`
- `dpdk`优化了什么
- `KNI`机制
- `DPDK`的技术边界
- `DPDK`能做什么
- 五、`DPDK`该怎么学
- 六、`coding`
- `rte_eal_init(argc, argv)`初始化`dpdk`应用
- `rte_pktmbuf_pool_create`创建
- 对网口的配置
- 接受数据
- 使用`API`接受数据
- 循环遍历解析所有接受到的包
- **关于`dpdk`无法接收来自主机的数据解决**
- 重启虚拟机后需要做的事
零、从0
开始配置dpdk
环境的虚拟机
外部配置
配置网卡
初始网卡选择桥接模式作为
dpdk
运行的网卡,添加第二张网卡NAT
模式用于ssh
连接内存与
CPU
核数选择- 内存选择
8g
以上,核数选择8
核以上
- 内存选择
修改源文件让网卡支持多队列
- 修改虚拟机的
vmx
文件,修改ethernet0.virtualDev = "e1000"
的值并添加一行
ethernet0.virtualDev = "vmxnet3" ethernet0.wakeOnPcktRcv = "TRUE"
- 修改虚拟机的
内部配置
配置网卡
在安装``ubunt_userver
时,存在多个网卡时需要选择默认网关网卡,这里选择用于
ssh连接网卡
ens33`ens160
是多队列网卡,配置其静态ip
地址,在/etc/network/interface
追加下面行auto ens160 iface ens160 inet static address 10.17.43.34 netmask 255.255.0.0
ip
需要根据主机的ip
地址的网段和掩码一致,因为这是桥接模式,第二章nat
网卡直接使用dhcp
自动获取ip
网关dns
服务器即可使用
route -n
可以查看默认网关
修改系统启动参数
修改
etc/default/grub
文件GRUB_CMDLINE_LINUX_DEFAULT="" GRUB_CMDLINE_LINUX="" >>>>修改后 GRUB_CMDLINE_LINUX_DEFAULT="quiet" GRUB_CMDLINE_LINUX="find_preseed=/preseed.cfg noprompt net.ifnames=0 biosdevname=0 default_hugepages=1G hugepagesz=2M hugepages=1024 isolCPUs=0-2"
修改后
update-grub
后reboot
会发现网卡名字变为了eth*
,此时修改/etc/network/interfaces
文件eth0
对应第一张也就是桥接模式的网卡,就替换ens160
eth1
替换ens33
一、dpdk
的编译usertool/dpdk-setup.sh
下载
dpdk-19.08.2
,在dpdk-stable-19.08.2
文件夹下执行./usertools/dpdk-setup.sh
选择不带
app
的x86_64-native-linux-gcc[39]
,因为它可以改源码设置运行时环境变量
export RTE_SDK=/home/ljq/share/module/dpdk-stable-19.08.2/
设置运行时环境的目标
export RTE_TARGET=x86_64-native-linux-gcc
./usertools/dpdk-setup.sh
选择[43] or [44]
插入IGB_UIO
模块or
插入V
选择
[45]
插入KNI
模块选择
[46] or [47]
巨页的配置46
代表采用no numa
方式管理多内存编号,47
代表采用numa
方式管理多内存编号numa
表示不是同一的编码方式,每个内存块都从索引0
开始,no-numa
表示同一编码方式,内存块之间的索引是连着的写
512
来设置1g
的巨页
选择
[49] or [50]
把对应网卡的绑定设备绑定在哪个模块上
[49]->UIO
[50]->VFIO
两者选一个 我选
49
接着输入
PCI
地址来绑定IGB UIO
找到
eth0
对应的行,输入其前面的数字字符串 我的是0000:03:00.0
回车后会警告:
Warning: routing table indicates that interface 0000:03:00.0 is active. Not modifying OK
,意思是还在工作中 没有修改成功我们要给他
down
掉,就是不让对应的NIC
接收数据,让dpdk
去绑定这个网卡去截获,网卡的数据就不会往内核里面走了ifconfig eth0 down
再次选择
49
,输入0000:03:00.0
后绑定成功此时
ifconfig
是不存在eth0
,也就是说明此时eth0
对应的NIC
不会再去接管他了,之后所有数据就是走到dpdk
里面了
编译前需要安装的
sudo apt-get install libnuma-dev libpcap-dev make
dpdk
接管网卡的两种方式
- 通用型
IO
- 虚拟
IO
注意有可能45出会出现错误,此时使用
grep CONFIG_RTE_KNI /boot/config-$(uname -r)
查看CONFIG_RTE_KNI
是否被设置为了m
或者y
,如果没有则需要手动添加进去
二、dpdk
需要什么配置来支持
1.多队列网卡
dpdk
要指定用哪一个队列来接收数据
2.巨页
三、解析接收网络数据的过程经历了什么
1.物理网卡
- 物理网卡接收(
vmware
的网络适配器就是一个网卡,是vmware
模拟的) - 物理网卡是光信号或者电信号与数字信号的相互转换
2.NIC
- 接收后每个网卡都会配对的有一个网络适配器(
NIC
)- 问题,
NIC
什么数据结构存? - 使用
ifconfig
就是查看NIC
的数量以及相关信息 - 网卡每来一帧数据
NIC
都会将它组织成sk_buff
(其中有很多指针,指向数据包中的各个层的头部),发送给协议栈,协议栈就解析其各个头
- 问题,
3.内核协议栈
NIC
把数据抛给内核协议栈,协议栈解析其sk_buff
中指向的各个头,注意这个协议栈是所有网卡共用的- 协议栈与
NIC
驱动的数据交互是怎样的- 网卡每来一帧数据
NIC
都会将它组织成sk_buff
(其中有很多指针,指向数据包中的各个层的头部),发送给协议栈,协议栈就解析其各个头
- 网卡每来一帧数据
- 协议栈与
4.标准接口层Posix API
- 标准接口层调用各种网络系统调用
5. 应用层
应用层就接收到了…
上述过程发生的拷贝
网卡数据拷贝到
NIC
,组织出sk_buff
APP
调用recv..
将数据从内核态拷贝到用户态上述操作需要
CPU
的参与
四、DPDK
介绍
基于上述接收网络数据流程dpdk
做的事
把网卡通过一种映射的方式,把网卡接收数据的存储空间映射到用户态的内存空间中,
这其中没有拷贝,是通过
DMA
的方式,直接网络适配器与硬盘驱动器与内存交互dpdk
主要做的事:把网卡的数据快速转移到用户态内存里
dpdk
如何组织映射的数据
Huge Page
- 正常的内存操作,一个页
4k
,假设一秒钟来了1
个G
的数据,那么4k
的页划分的包就为256x1024
,太多了,于是dpdk
采用巨页
dpdk
优化了什么
对thread
做CPU
的亲缘性
- 某一线程只在同一个
CPU
上运行
KNI
机制
用dpdk
只想处理一种协议,其他协议还是通过内核协议栈来处理
dpdk
提供了一种方式,将不需要的数据写入到内核协议栈,内核网络接口(Kernel Network Interface<kni>
)
DPDK
的技术边界
dpdk
处理数据时是跨过了NIC
这一层,在NIC
接收数据前就截获了数据,与NIC
平级,改变了数据流程
DPDK
能做什么
- 路由器、
SDN
网络定制开发 - 网络协议栈
- 防火墙,防
ddos
攻击- 接收数据,检测异常数据
VPN
- 直接往原始数据中加入
vxline
或加上隧道技术再从网卡中发送出去
- 直接往原始数据中加入
五、DPDK
该怎么学
环境搭建完后该做的事
coding
,代码可控- 实现一个协议栈(
eth,ip,arp,icmp,tcp,udp
) posix api, epoll
的实现
- 实现一个协议栈(
- 协议栈是与dpdk相生相辅
- 行业的应用
- 三层网络层的
vpp
- 二层传输层考虑
ovs
- 负载均衡
dpvs
- 发包工具
pktgen
- 三层网络层的
- 做
1-2
款上线的产品。。。
六、coding
rte_eal_init(argc, argv)
初始化dpdk
应用
rte_pktmbuf_pool_create
创建
rte_pktmbuf_pool_create(const char * name,unsigned int n, // 初始化mbufpoll池能放多少个mbufunsigned int cache_size, // 0uint16_t priv_size, // 0unit16_t data_room_size,int socket_id // 设置为一个全局的一个变量per_lcore_socket_id
);
// 返回一个rte_mempoll结构体
- 名字中的
mbuf
就是内核中的sk_buf
name
:Packet Buffer
池的名称,可以是任何字符串,建议使用有意义的名称。n
:Packet Buffer
池中Packet Buffer
的数量,建议设置为大于等于1024
。cache_size
:Packet Buffer
池中的本地缓存大小,可以根据使用场景进行调整,建议设置为Packet Buffer
数量的1/8
左右。priv_size
:Packet Buffer
中每个Packet Buffer
的私有数据大小,如果不需要私有数据,则可以设置为0
。data_room_size
:Packet Buffer
中数据区域的大小,即可以存储数据包的空间大小,建议设置为2048
或更大。socket_id
:用于分配内存的NUMA
节点编号,建议设置为套接字绑定的CPU
所在的NUMA
节点编号。
对网口的配置
在TCP/IP
网络中,当一个网络设备接收到来自其他设备的数据包时,就会触发RX
操作,将数据包解析并交给上层协议或应用程序
tx与rx是什么分别用在什么地方
txqueue
主要用于管理应用程序待发送的数据包,当应用程序需要向网络中发送数据时,首先将其封装成一个数据包,并添加到txqueue
中。
rxqueue
主要用于管理已经从网络中接收到的数据包,当网络中有数据包到达时,DPDK
会将其添加到rxqueue
中,应用程序可以从rxqueue
中取出数据包并进行进一步的处理。
// setupuint16_t nb_rx_queues = 1;uint16_t nb_tx_queues = 0;const struct rte_eth_conf port_conf_default = {.rxmode = {.max_rx_pkt_len = RTE_ETHER_MAX_LEN }};rte_eth_dev_configure(gDpdkPortId, nb_rx_queues, nb_tx_queues, &port_conf_default); // 设置第gDpdkPortId个绑定网口的信息,使用了索引为0对应的rx队列,设置了rx队列的大小为128,使用mbuf_pool来存储接收队列缓存rte_eth_rx_queue_setup(gDpdkPortId, // 设置第gDpdkPortId个绑定网口的信息0, // 使用了索引为0对应的rx队列128, // 设置了rx队列的大小为128rte_eth_dev_socket_id(gDpdkPortId), NULL, mbuf_pool); // 使用mbuf_pool来存储接收队列缓存// rte_eth_dev_start(gDpdkPortId);// disable//rte_eth_promiscuous_enable(gDpdkPortId); //
rte_eth_dev_configure
API介绍ret_eth_dev_configure(unit16_t port_id, //网口 nic 的id是什么unit16_t nb_rx_q, // rx队列 ,对应索引 0表示使用第一个unit16_t nb_tx_q, const struct rte_eth_conf* dev_conf // 配置信息 每个包的长度 );
port_id
:以太网设备的端口 ID。nb_rx_queue
:用于接收数据包的 RX 队列数量。nb_tx_queue
:用于发送数据包的 TX 队列数量。eth_conf
:一个结构体,包含了以太网设备的配置信息,如CRC
校验、硬件RSS
散列、速率控制,以及杂项配置等。
rte_eth_rx_queue_setup
API
介绍int rte_eth_rx_queue_setup(uint16_t port_id, // 要绑定的网口索引号 0代表使用第一个网口uint16_t rx_queue_id, // 要绑定的队列的索引,0代表绑定第一个rx队列uint16_t nb_rx_desc, // 指定队列可以装多少mbufunsigned int socket_id,const struct rte_eth_rxconf *rx_conf,struct rte_mempool *mb_pool );
port_id
:以太网设备的端口 ID。rx_queue_id
:将要创建的接收队列的队列号。nb_rx_desc
:用于网卡接收队列的缓存区描述符数量,可以简单理解为接收队列的缓存容量。(是网卡上面的rx_queue_id
对应id
的接收队列的大小,前面mbuf_pool
内存池的大小就是用来接收这个队列中的节点,所以这个内存池的大小肯定要比rx
队列大小大)socket_id
:用于分配和管理内存资源的NUMA
节点ID
,一般使用rte_socket_id()
函数获取。rx_conf
:用于指定接收队列的配置信息,如RSS
散列、哈希过滤器和Ptype
解析等特性。如果不需要使用这些特性,可以将该参数设置为NULL
。mb_pool
:用于存储接收队列缓存的内存池指针。
接受数据
while(1){//..后面的代码都在这个里面}
使用API
接受数据
struct rte_mbuf *mbufs[MBUF_SIZE]; // 32unsigned num_recvd = rte_eth_rx_burst(gDpdkPortId, // 绑定的网口0, // rx队列索引mbufs, MBUF_SIZE // 设置的32);if (num_recvd > MBUF_SIZE) {rte_exit(EXIT_FAILURE, "rte_eth_rx_burst Error\n");}
rte_eth_rx_burst
uint16_t rte_eth_rx_burst(uint16_t port_id, uint16_t queue_id,struct rte_mbuf **rx_pkts, // 传出参数const uint16_t nb_pkts); // 不需要考虑释放 在内存池中直接将对应id取出来直接用
port_id
:以太网设备的端口ID
。queue_id
:用于接收数据包的RX
队列ID
。rx_pkts
:指向rte_mbuf
结构体指针的数组,用于存储接收到的数据包。nb_pkts
:要读取的最大数据包数量。
循环遍历解析所有接受到的包
unsigned i = 0;
for (i = 0;i < num_recvd;i ++) {// 宏函数struct rte_ether_hdr *ehdr = rte_pktmbuf_mtod(mbufs[i], struct rte_ether_hdr *);if (ehdr->ether_type != rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4)) {continue;}struct rte_ipv4_hdr *iphdr = rte_pktmbuf_mtod_offset(mbufs[i], struct rte_ipv4_hdr *, sizeof(struct rte_ether_hdr));if (iphdr->next_proto_id == IPPROTO_UDP) {struct rte_udp_hdr* udphdr = (struct rte_udp_hdr*)(iphdr + 1); // 加上IP头得到udp头uint16_t length = udphdr->dgram_len;*((char*) udphdr + length - 1) = '\0';printf("udp: %s\n", (char*)(udphdr+1));}
}
rte_pktmbuf_mtod
是一个宏,而不是一个函数。在 DPDK
的rte_mbuf.h
文件中,可以看到rte_pktmbuf_mtod
的定义如下:#define rte_pktmbuf_mtod(m, t) ((t)((char *)((m)->buf_addr) + (m)->data_off))
这个宏的实现使用了强制类型转换,其目的是将缓冲区中数据的地址转换为用户指定的数据类型
t
的指针,从而方便用户访问和处理接收到的数据包。需要注意的是,在使用rte_pktmbuf_mtod
宏时,应当确保传入的参数合法,并且传入的数据类型和数据包的格式相符,否则可能会导致程序错误。
设置
arp
静态映射用
arp
静态映射 就可以用网络调试工具调试了注意设置的ip地址是要与本机网卡ip地址是同一个网段
arp -s 10.17.31.80 00-0C-29-AF-77-5Carp -d 10.17.31.80# The ARP entry addition failed: Access is deniednetsh i i show in # 查看网络接口的索引号netsh -c i i add neighbors 18 10.17.31.80 00-0C-29-AF-77-5Cnetsh -c "i i" delete neighbors 1
关于dpdk
无法接收来自主机的数据解决
保证绑定网卡前主机可以
ping
通虚拟机的eth0
的桥接网卡eth0
的ip
要在主机上静态绑定eth0
的mac
重启虚拟机后需要做的事
- 查看主机ip是否改变(连接不同的网络都会改变)
- 如果改变了就重新设置
/etc/network/interfaces
文件,设置eth
的静态ip
,需要与主机ip
为同一网段即可
- 如果改变了就重新设置
DPDK入门(环境搭建以及小demo)相关推荐
- NodeJS入门--环境搭建 IntelliJ IDEA
NodeJS入门–环境搭建 IntelliJ IDEA 本人也刚开始学习NodeJS,所以以此做个笔记,欢迎大家提出意见. 1.首先 下载安装NodeJS,下载安装IntelliJ IDEA 2.接下 ...
- Thingworx自定义扩展开发(一)- 开发环境搭建、Extension Demo Coding
系列 Thingworx自定义扩展开发(一)- 开发环境搭建.Extension Demo Coding Thingworx自定义扩展开发(二)- Widget Demo Coding Thingwo ...
- Linux入门-环境搭建、基本指令以及权限讲解
这次我给大家介绍Linux系统,究竟怎么更快上手Linux,怎么学习Linux?接下来我给大家分享一下干货. Linux入门 环境搭建 Linux指令 基本指令 ls命令 cd指令 安装软件的指令 r ...
- Hadoop入门·环境搭建
Hadoop入门·环境搭建 1 步骤 硬件环境准备 资源下载 环境部署 2 分布式集群环境部署 2.1 硬件环境准备 本案例中使用三台服务器(仅作为学习案例),分别为Hadoop102,Hadoop1 ...
- 【Swift-Vapor服务器】0001、Swift-Vapor入门-环境搭建
[Swift-Vapor服务器]系列 [Swift-Vapor服务器]0001.Swift-Vapor入门-环境搭建 技术:Swift5.7.Vapor4.0.服务器.本地服务器.Vapor基本使用 ...
- NS3 入门环境搭建
NS3 入门环境搭建3.30版本 环境:Windows10 + Ubuntu18.04双系统 环境:Windows10 + Ubuntu18.04双系统 1.添加源 sudo vim /etc/apt ...
- 普歌-云言团队-Spring Boot入门:环境搭建Spring Boot HelloWorld
Spring Boot入门:环境搭建Spring Boot HelloWorld 前言:SpringBoot 是来简化Spring应用开发, 约定大于配置, 去繁从简, just run就能创建一个独 ...
- 合泰杯 | 合泰单片机入门 环境搭建安装(一)
最近参加福建省的合泰杯比赛,第一次接触合泰单片机,一开始学习的是51 和 32 ,虽然各类单片机的操作都万变不离其中,但是相对于51和32 的资料,合泰单片机的资料对于新手来说就不那么友好了.所以后面 ...
- vue 入门环境搭建
公司项目要用vue.js来开发,要使用vue来开发前端框架,首先要有环境,所以给大家介绍一下如何搭建vue环境.其实很简单: 1.首先下载安装node.js. 去官网https://nodejs.or ...
最新文章
- zabbix 客户端安装
- 调试的时候step into,step out,step over有什么区别?各有什么作用?分别在什么情况下使用?
- deepin v20.1折腾美化之Plank dock任务栏安装
- SpringMVC整合Redis2.9.0
- Java网络编程从入门到精通(15):为什么要使用SocketAddress来管理网络地址
- 初学C语言2--C语言项目的基本框架
- 更新啦~人生重开模拟器自制
- centos修改mysql数据库密码修改_centos7 mysql 修改数据库密码
- sqlserver 日期与字符串之间的转换
- volatility命令
- Ubuntu Budgie 22.04 设置中文语言并安装拼音输入法
- aws mysql 多区_AWS RDS多可用区+EC2实例跑mysql从库的测试
- 2020南京航空航天大学计算机科学与技术学院软件工程复试/面试经验分享
- 宝峰对讲机16频率表_宝峰uv5r系列对讲机出厂预置频率表-手工编辑版
- 算法刷题重温(九): 排序算法来啦
- Putty 安装配置使用
- 执行 npm install -g grunt-cli 安装grunt发生错误问题
- [技术文档] 航顺芯片HK32F030MSO8N-J4M6开发板评测。航顺MCU
- requestPermissions读写手机存储权限_2020年新版手机QQ接受文件存在哪里?钛备份闪退等使用教程...
- vue 不同用户登录系统拥有不同查看菜单导航的权限