数据接收全流程图(物理网卡 → 应用层)
以下是 DPDK + VPP 在 Linux 系统中从网卡收包到应用层的完整数据流程图及分步解析,结合了内核旁路和用户态协议栈的协同工作:
数据接收全流程图(物理网卡 → 应用层)
plaintext
复制
下载
+------------------------------------------------------------------------------------+ | Linux 系统 | +------------------------------------------------------------------------------------+ | | | +------------+ DMA +-------------+ Zero-Copy +---------------------+ | | | 物理网卡 | ------> | DPDK PMD | ------------> | DPDK RX队列 | | | | (NIC) | <------ | (Poll Mode | <------------ | (rte_eth_rx_burst) | | | +------------+ 中断屏蔽 +-------------+ 轮询 +---------------------+ | | | | | v | | +---------------------+ 共享内存 +------------------+ 向量化传递 +--------+ | | | DPDK内存池 | <--------> | VPP输入节点 | ----------> | VPP | | | | (rte_mempool/mbuf) | | (ethernet-input) | | 图节点 | | | +---------------------+ +------------------+ +--------+ | | | | | v | | +------------------+ 协议解析 +------------------+ 路由决策 +-------------+ | | | VPP协议栈处理 | --------> | L3/L4处理 | --------> | 转发/本地交付 | | | | (ip4-input, etc.) | | (NAT, ACL, etc.) | | (local-node)| | | +------------------+ +------------------+ +-------------+ | | | | | v | | +------------------+ Socket API +------------------+ 系统调用 +-----------+ | | | 应用层Socket | <----------- | VPP Socket层 | <-------- | 用户应用 | | | | (TCP/UDP) | | (vcl, session) | | (如Nginx) | | | +------------------+ +------------------+ +-----------+ | | | +------------------------------------------------------------------------------------+
关键步骤详解
1. 网卡到DPDK(内核旁路)
-
物理层:
-
网卡通过 DMA 将数据包写入预分配的 DPDK内存池(rte_mempool)。
-
中断屏蔽:DPDK禁用网卡中断,改用主动轮询(
rte_eth_rx_burst
)。
-
-
零拷贝:
-
数据包始终驻留在用户态内存(
rte_mbuf
),避免内核拷贝。
-
2. DPDK到VPP输入节点
-
向量化传递:
-
DPDK批量接收的数据包(如64个)通过 共享内存 传递给VPP的
ethernet-input
节点。
-
-
协议识别:
-
VPP解析以太网头,决定下一跳节点(如
ip4-input
或ip6-input
)。
-
3. VPP协议栈处理
-
L3/L4处理:
-
IP层:路由查找(FIB)、分片重组。
-
传输层:TCP/UDP校验、NAT转换(如
nat44-in2out
节点)。
-
-
本地交付判断:
-
若目的IP为本地,数据包进入
local-node
节点,准备提交给应用层。
-
4. VPP到应用层
-
Socket抽象层:
-
VCL (VPP Communication Library):提供兼容Linux Socket的API(如
socket()
、recv()
)。 -
Session层:管理连接状态(类似内核的
struct sock
)。
-
-
数据交付:
-
应用调用
recv()
时,VCL从VPP的Session层直接获取数据,无需经过内核协议栈。
-
性能优化点
-
全用户态路径:
-
从网卡到应用全程无内核参与,减少上下文切换。
-
-
批处理与向量化:
-
DPDK和VPP均以批量方式处理数据包(如每次处理64个包)。
-
-
内存池化:
-
rte_mempool
复用内存块,避免动态分配开销。
-
-
CPU亲和性:
-
绑定DPDK轮询线程和VPP Worker线程到独立CPU核。
-
与传统内核协议栈的对比
步骤 | DPDK + VPP | 传统内核协议栈 |
---|---|---|
数据接收 | 用户态轮询(零拷贝) | 中断 + NAPI(内核拷贝) |
协议处理 | 用户态向量化节点 | 内核逐层处理(ip_rcv, tcp_v4_rcv) |
Socket通信 | VCL库直接对接VPP | 内核Socket缓冲区拷贝 |
延迟 | 微秒级 | 毫秒级 |
吞吐量 | 1M+ PPS/core | 100K~500K PPS/core |
典型应用场景
-
高性能代理(如Nginx):
-
VPP替代内核TCP栈,Nginx通过VCL库直接接收HTTP请求。
-
-
金融交易系统:
-
微秒级延迟处理市场数据(UDP组播 + VPP快速转发)。
-
-
5G UPF:
-
GTP-U解封装后直接转发至用户态应用。
-
调试命令示例
-
查看VPP数据流:
bash
复制
下载
vpp# show trace # 追踪数据包路径 vpp# show session # 查看当前连接
-
监控DPDK统计:
bash
复制
下载
dpdk-proc-info --mempool-stats # 内存池使用情况
如果需要更深入的特定环节(如VCL实现细节或NAT性能优化),可进一步展开!
一个系统既有Linux 内核又有,vpp,tcp通信是如何确定数据是走的vpp还是Linux内核协议栈呢
在一个同时运行 Linux 内核协议栈 和 VPP(用户态协议栈) 的系统中,TCP/IP 通信路径的选择取决于 网络接口绑定、路由规则、应用配置 等多个因素。以下是决定数据流走向的核心机制和配置方法:
1. 关键区分因素
因素 | 走 VPP | 走 Linux 内核协议栈 |
---|---|---|
网卡绑定 | 网卡由 DPDK 接管(如绑定 igb_uio ) | 网卡由内核驱动管理(如 igb ) |
应用 Socket 类型 | 使用 VPP 的 VCL (VPP Communication Library) | 标准 Linux Socket API(如 AF_INET ) |
路由规则 | VPP 控制的路由表(FIB) | 内核路由表(ip route ) |
接口 IP 配置 | IP 地址配置在 VPP 接口(set int ip ) | IP 地址配置在内核接口(ip addr ) |
2. 具体控制方法
(1) 网卡绑定与归属
-
VPP 接管网卡:
bash
复制
下载
# 使用 DPDK 绑定网卡(如 eth0)到用户态,脱离内核控制 sudo dpdk-devbind.py --bind=igb_uio eth0
-
此后,该网卡的数据包 不再进入内核协议栈,只能通过 VPP/DPDK 处理。
-
-
内核保留网卡:
-
未绑定 DPDK 的网卡(如
eth1
)仍由内核驱动管理,走传统协议栈。
-
(2) 应用层 Socket 选择
-
走 VPP 的通信:
-
应用需链接 VCL 库,替换标准 Socket 调用:
c
复制
下载
#include <vcl/vppcom.h> int fd = vppcom_socket(AF_INET, SOCK_STREAM, 0);
-
适用场景:高性能代理(如 Nginx 适配 VPP)、自定义用户态协议栈。
-
-
走内核的通信:
-
使用标准
glibc
Socket API:c
复制
下载
#include <sys/socket.h> int fd = socket(AF_INET, SOCK_STREAM, 0);
-
(3) 路由与 IP 配置
-
VPP 路由控制:
bash
复制
下载
vpp# set int ip address dpdk0 192.168.1.1/24 vpp# ip route add 10.0.0.0/8 via 192.168.1.2
-
目标地址匹配 VPP 路由表时,数据由 VPP 转发。
-
-
内核路由控制:
bash
复制
下载
sudo ip addr add 192.168.1.1/24 dev eth1 sudo ip route add default via 192.168.1.2
-
目标地址匹配内核路由表时,走内核协议栈。
-
(4) 混合场景的流量引导
-
KNI (Kernel NIC Interface):
-
允许 VPP 将特定流量转发到内核:
bash
复制
下载
vpp# create interface kni name kni0 vpp# set interface ip address kni0 10.0.0.1/24
-
用途:需要内核处理的管理流量(如 SSH、DNS)。
-
-
策略路由:
-
使用
ip rule
按源IP/端口选择路径:bash
复制
下载
sudo ip rule add from 192.168.1.100 table 100 # 走 VPP sudo ip rule add from 192.168.1.200 table 200 # 走内核
-
3. 典型场景示例
场景 1:高性能 Web 服务器
-
目标:让 Nginx 通过 VPP 处理 HTTP 流量。
-
配置:
-
绑定物理网卡到 DPDK(脱离内核)。
-
在 VPP 中配置 IP 和路由。
-
重新编译 Nginx,链接 VCL 库替代标准 Socket。
-
场景 2:混合流量处理
-
目标:业务流量走 VPP,管理流量走内核。
-
配置:
-
保留一个物理网卡(如
eth1
)给内核。 -
通过 KNI 将 VPP 的管控流量(如 ICMP)转发到内核。
-
使用策略路由区分流量类型。
-
4. 检查数据流路径的工具
-
确认网卡归属:
bash
复制
下载
sudo dpdk-devbind.py --status # 查看网卡是否被 DPDK 绑定
-
查看 VPP 接口状态:
bash
复制
下载
vpp# show interface
-
内核路由表:
bash
复制
下载
ip route show
-
抓包验证:
-
VPP 路径:
vpp# trace add dpdk-input 10
-
内核路径:
tcpdump -i eth1
-
5. 总结
-
数据走 VPP:网卡绑定 DPDK + 应用使用 VCL + VPP 路由配置。
-
数据走内核:网卡未绑定 DPDK + 标准 Socket + 内核路由配置。
-
混合路径:通过 KNI 或策略路由动态分流。
通过合理配置,可以精确控制哪些流量由 VPP 加速,哪些仍需内核处理,兼顾性能与兼容性。