-
****
DPDK
学习
L2
fwd
代码走读报告
导师:
***
学生:
***
2016-2-18
目录
一、
对于
DPDK
的认识:
.
.................................
..................................................
............................
2
二、对
L2
fwd
的认识:
.
< br>............................................... .................................................. ................
3
2.1
运行配置
...................
..................................................
..................................................
......
3
2.2
运行环境搭建
.
..................................
..................................................
................................
3
2.3
功能分析:
< br>.
...................................
..................................................
...................................
6
2.4
详细流程图(调用关系)如下:
.
...........................
..................................................
.......
6
2.5
运行截图
............................
..................................................
...............................................
8
2.6
详细代码注释分析:
.
...............................
..................................................
.......................
8
一、对于
DPDK
的认识:
主要应用
x86
通用平台
,
转发
处理
网络数据包,
定位在不需要专用网络处理器,
但通用网络处理器对数据处理性能又不能满足需求的客户。
DPDK
,搭载
x86
服务器
,成本变化不大,但对数据的处理性能又有非常显著
的提高,
对
传统
linux
技术做一定的优化,
特
别之处在于:
hugepage,uio,zero copy,
cpu affinity
等。
p>
关于
hugetlbpage
(
在这块大页面上做自己的内存管理系统)
,之前讲过,它
< br>的主要好处当然是通过利用大内存页提高内存使用效率,。由于
DPDK
是应用层平
台,所以与此紧密相连的网卡驱动程序(当然,主要是
intel
自身的千兆
igb
与万
兆
ixgbe
驱动程序)
都通过
uio(
用户层驱动、轮询、
0
拷贝
)
机制运行在用户态下。
cpu affinity
(
多核架构,核线程
绑定物理核)
机制是多核
cpu
发展的
结果,,在越
来越多核心的
cpu
机器
上,
如何提高外设以及程序工作效率的最直观想法就是让各
个<
/p>
cpu
核心各自干专门的事情,比如两个网卡
eth0
和
eth1
都收包,可以
让
cpu0
专心处理
eth0
,
cpu1
专心处理
e
th1
,没必要
cpu0
一下处理
p>
eth0
,一下又处理
eth1
,还有一个网卡多队列的情况也是类似,等等,
DPDK
< br>利用
cpu affinity
主要
是将控制面线程以及各个数据面线程绑定到不同的
cpu
,
省却了来回反复调度的性
能消耗,各个线程一个
while
p>
死循环,专心致志的做事,互不干扰(当然还是有通
信的,比如控制
面接收用户配置,转而传递给数据面的参数设置等)。
总结如下:
1
、
使用大页缓存支持来提高内存访问效率。
2
、
利用<
/p>
UIO
支持,提供应用空间下驱动程序的支持,也就是说网卡驱动
是运
行在用户空间
的,减下了报文在用户空间和应用空间的多次拷贝。
3
、
p>
利用
LINUX
亲和性支持,把控制面线程
及各个数据面线程绑定到不同的
CPU
核,节省了
线程在各个
CPU
核来回
调度。
4
、
提供内存池和无锁环形缓存管理,加快内存访问效率。
在
x86
服务器,
1
G/10G/40G
网卡包转发,
64Byte
小包,基本能做到
70%
以
上
的转发,而传统
linux
系统只能达
5%
左右,在网络大数据流时代,
DPDK
加码,
优势明显。
二、对
L2fwd
的认识:
2.1
运行配置
虚拟机软件:
VMWare WorkStation
12.0.0 build-2985596
CPU
:
2
个
CPU
,
每个
CPU2
个核心
< br>
内存:
1GB+
网卡:
intel
网卡
*2
,
用于
dpdk
试验;另一块网卡用于和宿主系统进行通信
2.2
运行环境搭建
在
root
权限下:
1
)编译
dpdk
< br>进入
dpdk
主目录
,输入
make install
T=x86_64-native-linuxapp-
gcc
进行编译
2
< br>)配置大页内存(非
NUMA
)
echo 128 >
/sys/kernel/mm/hu
gepages/hugepages-2048kB/nr_hugepages
mkdir /mnt/huge
mount -t
hugetlbfs nodev /mnt/huge
可以用以下命令查看大页内存状态:
cat /proc/meminfo | grep Huge
3
)安装
igb_uio
驱动
p>
modprobe uio
insmod x86_64-native-linuxapp-
gcc/kmod/igb_
4
)绑定网卡
先看一下当前网卡的状态
./tools/dpdk_nic_ --status
图
1
网卡已经绑定好
进行绑定:
./tools/dpdk_nic_ -b igb_uio
0000:02:06.0
./tools/dpdk_nic_ -b
igb_uio 0000:02:05.0
如果网卡有接口名,如
eth1, eth2,
也可以在
-b
igb_uio
后面使用接口名,
而
不使用
pci
地址。
< br>
5 )
设置环境变量:
export RTE_SDK=/home/lv/dpdk/dpdk-1.7.0
export RTE_TARGET=x86_64-native-
linuxapp-gcc
之后进入
,运行
make
,成功
会生成
build
目录,其中
有编译好
的
l2fwd
程序。
6)
运行程序
./build/l2fwd -c f -n 2 -- -q 1 -p 0x3
2.3
功能分析:
DPDK
搭建环境完成后,网卡绑定
到相应
IGB_UIO
驱动接口上,所有的网络数
据包都会到
DPDK
,网卡接收网络数据包,再从另
一个网卡转发出去
2.4
详细流程图(调用关系)如下:
(
初学者,欢迎讨论
QQ:78010
2849
,望各位指错
)
DPDK
L2fwd
详细流程图(调用关系)
main
rte_eal_init
Pthread_create
init
Other inits
(
libs<
/p>
,
drivers
)
Pthread_cr
eate
init
Pthread_c
reate
init
rte_eal_mp_remote_launch
Lcore 1
(
SLAVE
)
rte_eal_remote_launch
(send
messages to cores)
Lcore 2
(
SLAVE
)
L
core
……
(
S
LAVE
)
lcore_config[master].ret = f(arg);
Master Lcore
rte_eth_rx
_burst
(Read
packet
from RX
queues)
l2fwd_se
nd_burst
(enough
pkts to
be sent)
rte_eth_
rx_burst
(Read
packet
from
RX
queues)
l2fwd_se
nd_burst
(enough
pkts to
be
sent)
eth0
eth1
eth 2
eth 3
lcore_config[master].state
= FINISHED;
return 0 (end)
2.5
运行截图
2.6
详细代码注释分析:
1
#include
2
#include
3
#include
<
string
.h>
4
#include
5
#include
6
#include
7
#include
8
物理端口的 ,
#include
in
.h>
9
#include
10
#include
11
#include
12
#include
13
#include
14
15
#include
16
#include
17
#include
18
#include
19
#include
20
#include
21
#include
22
#include
23
#include
24
#include
25
#include
26
#include
27
#include
28
#include
29
#include
30
#include
31
#include
32
#include
33
#include
34
#include
35
#include
36
#include
37
#include
38
39
#define
RTE_LOGTYPE_L2FWD
RTE_LOGTYPE_USER1
40
41
#define
MBUF_SIZE (2048 + sizeof(struct rte_mbuf) +
RTE_PKTMBUF_HEADROOM)
42
#define
NB_MBUF 8192
43
44
#define
MAX_PKT_BURST 32
45
#define
BURST_TX_DRAIN_US 100 /* TX drain every ~100us */
46
47
/*
48
* Configurable number of RX/TX ring
descriptors
49
*/
50
#define
RTE_TEST_RX_DESC_DEFAULT 128
51
#define
RTE_TEST_TX_DESC_DEFAULT 512
52
static
uint16_t nb_rxd =
RTE_TEST_RX_DESC_DEFAULT;
53
static
uint16_t nb_txd =
RTE_TEST_TX_DESC_DEFAULT;
54
55
/*
mac
地址的数组
ethernet addresses of ports */
56
staticstruct
ether_addr l2fwd_ports_eth_addr[RTE_MAX_ETHPORTS];
57
58
/*
已经启用的物理端口的掩码
/
位
图
mask of enabled ports
*/
59
static
uint32_t
l2fwd_enabled_port_mask =
0
;
60
61
/*
已经启用的目的物理端口编号的数组
list
of enabled ports */
62
static
uint32_t
l2fwd_dst_ports[RTE_MAX_ETHPORTS];
63
64
static
unsigned
int
l2fwd_rx_queue_per_lcore
=
1
;
//
默认值,每个
lcore
负责
的接收
队列数量
65
66
struct
mbuf_table {
//mbuf
数组,可以存放<
/p>
32
个数据包
67
unsigned len;
68
struct
rte_mbuf
*m_table[MAX_PKT_BURST];
69
};
70
71
#define
MAX_RX_QUEUE_PER_LCORE 16
72
#define
MAX_TX_QUEUE_PER_PORT 16
73
struct
lcore_queue_conf {
74
unsigned n_rx_port;
//
用于接收数据包的物理端口的实际数量
75
unsigned
rx_port_list[MAX_RX_QUEUE_PER_LCORE];
76
struct
mbuf_table
tx_mbufs[RTE_MAX_ETHPORTS];
//
保存发送数据包的缓存区
77
78
} __rte_cache_aligned;
79
struct
lcore_queue_conf
lcore_queue_conf[RTE_MAX_LCORE];
80
81
staticconststruct
rte_eth_conf port_conf = {
82
.rxmode = {
83
.split_hdr_size =
0
,
84
.header_split =
0
,
/**< Header Split disabled
*/
85
.hw_ip_checksum =
0
,
/**< IP checksum offload disabled
*/
86
.hw_vlan_filter =
0
,
/**< VLAN filtering disabled
*/
87
.jumbo_frame =
0
,
/**< Jumbo Frame Support disabled
*/
88
.hw_strip_crc =
0
,
/**< CRC stripped by hardware
*/
89
},
90
.txmode = {
91
.mq_mode =
ETH_MQ_TX_NONE,
92
},
93
};
94
95
struct
rte_mempool *
l2fwd_pktmbuf_pool = NULL;
96
97
/*
每个物理端口的统计结构体
Per-port statistics struct */
98
struct
l2fwd_port_statistics {
99
uint64_t tx;
100
uint64_t rx;
101
uint64_t dropped;
102
}
__rte_cache_aligned;
103
struct
l2fwd_port_statistics
port_statistics[RTE_MAX_ETHPORTS];
//
p>
数据包
的统计信息的全局数组
104
105
/* A tsc-based timer
responsible for triggering statistics printout
*/
106
#define
TIMER_MILLISECOND 2ULL /* around 1ms at 2 Ghz */
107
#define
MAX_TIMER_PERIOD 86400 /* 1 day max */
108
static
int64_t
timer_period =
10
*
TIMER_MILLISECOND *
1
;
/* default peri
od is 10
seconds */
109
110
/* Print out statistics
on packets dropped */
static
void
//
打印数据包丢失等统计信息
112
print_stats(
void
)
113
{
114
uint64_t
total_packets_dropped, total_packets_tx,
total_packets_rx;
115
unsigned portid;
116
117
total_packets_dropped =
0
;
118
total_packets_tx =
0
;
119
total_packets_rx =
0
;
120
121
constchar
clr[] = {
27
,
'['
,
'2'
,
'J'
,
'0'
};
122
constchar
topLeft[] = {
27
,
'['
,
'1'
,
';'
,
'1'
,
'H'
'0'
};
123
124
/* Clear screen and move
to top left */
125
printf(
, clr, topLeft);
126
127
printf(
);
128
129
for
(portid =
0
; portid <
RTE_MAX_ETHPORTS; portid++) {
130
/* skip disabled ports
*/
131
if
((l2fwd_enabled_port_mask &
(
1
<< portid)) ==
0
)
132
continue
;
133
printf(
134
PRIu64
135
PRIu64
136
PRIu64,
137
portid,
138
port_statistics[portid].tx,
139
port_statistics[portid].rx,
140
port_statistics[portid].dropped);
141
142
total_packets_dropped +=
port_statistics[portid].dropped;
143
total_packets_tx
+= port_statistics[portid].tx;
144
total_packets_rx
+= port_statistics[portid].rx;
145
}
146
printf(
147
PRIu64
148
PRIu64
149
PRIu64,
150
total_packets_tx,
151
total_packets_rx,
152
total_packets_dropped);
153
printf(
);
154
}
155
156
/* Send the burst of
packets on an output interface */
157
staticint
//
< br>在一个输出接口上
burst
发送数据包
158
l2fwd_send_burst(
struct
lcore_queue_conf *qconf, unsigned n, uint8_t
por
t)
159
{
160
struct
rte_mbuf **m_table;
161
unsigned ret;
162
unsigned queueid =
0
;
163
164
m_table =
(
struct
rte_mbuf
**)qconf->tx_mbufs[port].m_table;
165
p>
//burst
输出数据包
166
ret =
rte_eth_tx_burst(port, (uint16_t) queueid,
m_table, (uint16_t)
n);
167
port_statistics[port].tx += ret;
//
记录发包数量
168
if
(unlikely(ret < n)) {
169
port_statistics[port].dropped += (n - ret);
//
记录丢包数量
170
do
{
171
rte_pktmbuf_free(m_table[ret]);
172
}
while
(++ret < n);
173
}
174
175
return
0
;
176
}
177
178
/* Enqueue packets for TX
and prepare them to be sent */
< br>179
staticint
//
把数据包入队到发送缓冲区
180
l2fwd_send_packet(
struct
rte_mbuf *m, uint8_t port)
181
{
182
unsigned lcore_id,
len;
183
struct
lcore_queue_conf *qconf;
184
185
lcore_id =
rte_lcore_id();
//
取得正在运行的
lcore
编号
186
187
qconf = &lcore_queue
_conf[lcore_id];
//
取得
< br>lcore_queue
的配置
188
len =
qconf->tx_mbufs[port].len;
//
得到发包缓存区中数据包的个数
189
qconf->tx_mbufs[port].m_table[len] =
m;
//
指向数据包
190
len++;
191
192
/* enough pkts to be sent
*/
193
if
(unlikely(len == MAX_PKT_BURST)) {
//
p>
如果累计到
32
个数据包
< br>
194
l2fwd_send_burst(qconf, MAX_PKT_BURST, port);
//
实际发送数据包
195
len =
0
;
196
}
197
198
qconf->tx_mbufs[port].len = len;
//
更新发包缓存区中的数据包的个数
199
return
0
;
200
}
201
202
staticvoid
203
l2fwd_simple_forward(
struct
rte_mbuf *m, unsigned portid)
204
{
205
//
想要满足文生提出的需求,主要在这里修改
ip<
/p>
层和
tcp
层的数据内容。
206
207
struct
ether_hdr *eth;
208
void
*tmp;
209
unsigned dst_port;
210
211
dst_port =
l2fwd_dst_ports[portid];
212
eth =
rte_pktmbuf_mtod(m,
struct
ether_hdr *);
213
214
/* 02:00:00:00:00:xx
修改目的
mac
地址
*/
215
tmp =
ð->d__bytes[
0
];
-
-
-
-
-
-
-
-
-
上一篇:英语绕口令大全超难
下一篇:综合教程大学英语4课本译文及课后答案