全部博文(930)
分类: LINUX
2010-04-08 17:17:30
在千兆网环境下,tcpdump丢包率相当高。网上搜了很多制标不治本的方法,比如增大缓冲区,然而缓冲区再大也有塞满的时候,只能从驱动和硬件下手。好在有“零拷贝(Zero Copy)”这个东西(说白了也就是通过DMA等方式,省掉从NPF驱动到用户程序内存空间的一次复制,给CPU减少负担),而PF_RING正是一个通过给Linux内核打补丁来实现zero copy的强大工具,于是想给Fedora集成个PF_RING。
没接触过Linux内核,网上这方面资料都是Ubuntu的,和Fedora下有点不同。摸了近2周才把PF_RING给补上,记录一下详细编译过程,以免以后又走弯路。
另一篇关于Fedora 9下编译的文章:http://guotie.blogbus.com/logs/29668826.html
本文中的编译过程, 在Fedora 7和Fedora 9下(实机和虚拟机)均测试通过(来来回回编译了内核5遍,不熟也熟了...)
文章中没有需要单独下载的压缩包,内核源码也建议使用PF_RING自带的mkpatch.sh来下载(或者下完放到workspace目录中)
首先,按照正常步骤,下载PF_RING(粗体是要输入的命令,我的PF_RING存放目录是 /home/kernel):
cd /home/kernel
svn co
等下载完成后,/home/kernel 下多了一个PF_RING的目录。
cd PF_RING
# ll
total 36
drwxr-xr-x 3 root root 4096 2009-03-17 16:26 doc
drwxr-xr-x 5 root root 4096 2009-03-17 16:26 kernel
-rwxr-xr-x 1 root root 14678 2009-03-20 22:48 mkpatch.sh
-rw-r--r-- 1 root root 643 2009-03-17 16:26 README
drwxr-xr-x 8 root root 4096 2009-03-17 16:26 userland
uname -a 或者 uname -r 确定内核版本(建议使用一样的内核源文件编译,这样配置起来方便点)
vi mkpatch.sh 修改内核版本号 SUBLEVEL=${SUBLEVEL:-24.7}
默认是-24.7,这里用你 uname -r 获取的版本来代替,例如
# uname -r 显示2.6.25-14.fc9.i686,则改成 SUBLEVEL=25
./mkpatch.sh
下载内核到workspace中,生成目录linux-2.6.25-1-686-smp-PF_RING和补丁文件linux-2.6.25-1-686-smp-PF_RING.patch.gz,如下
# ll
total 60220
drwxr-xr-x 22 root root 4096 2009-03-21 20:43 linux-2.6.25
drwxr-xr-x 21 root root 4096 2008-04-17 10:49 linux-2.6.25-1-686-smp-PF_RING
-rw-r--r-- 1 root root 63254 2009-03-20 22:50 linux-2.6.25-1-686-smp-PF_RING.patch.gz
-rw-rw-r-- 1 zhou zhou 61517918 2009-03-20 22:45 linux-2.6.25.tar.gz
lrwxrwxrwx 1 root root 25 2009-03-20 22:49 PF_RING -> /home/zhou/kernel/PF_RING
这里不建议直接用生成的linux-2.6.25-1-686-smp-PF_RING这个源码,之前出问题都是在这个上面,还是按PF_RING手册上说得给干净内核打补丁来得稳妥。另外,没有特殊需要,不建议使用其他教程里提及的Fedora RPM源码包(kernel-2.6.25-14.fc9.src.rpm),make时会出现些莫名奇妙的错误。
按下面操作把这个目录给改名掉,然后手动给原始内核打补丁:
mv linux-2.6.25-1-686-smp-PF_RING/ linux-2.6.25-1-686-smp-PF_RING.bak/
zcat linux-2.6.25-1-686-smp-PF_RING.patch.gz | patch -p0 # 给 linux-2.6.25/ 下的源码打补丁
然后显示一串被补丁的文件,OK。(注意,如果是干净内核,应该不会提示任何是否覆盖已有patch之类的信息。如果出现这个,建议重新解压内核打补丁)
这是关键一步,建议仔细检查一下打补丁的目录是否是linux-2.6.25/下的文件!
下面准备编译内核,首先给内核加个后缀名,以便标识:
cd linux-2.6.25
# vi Makefile 在这个地方加上一个自定义的后缀(比如-PF_RING):
EXTRAVERSION = -PF_RING
配置并编译内核!(灰色指令是可选的)
make mrproper # (不建议)清除以前编译的内核文件。因为是新解压的,保持原始状态就好,不建议用这个
make oldconfig # 读取当前内核的配置(相当重要,这步能省好多配置工作,而且保证生成的.config能直接使用)
# 其间会提示 PF_RING xxxx [N/y/m/?] (NEW) ,注意按y选择把PF_RING给加进去,其他的选择按回车默认即可
# 不过注意,如果编译的内核版本较当前的新,会有很多(NEW)标记的提示,此时要是找不到PF_RING,建议先全部回车跳过
make menuconfig # 如果之前把PF_RING也跳过了,这里可以进去重新选上
Networking --->
Networking options --->
PF_RING sockets (NEW)
这里按y选上PF_RING,然后保存修改到.config退出。
(PF_RING手册上说还要选上其他几个,不过我没找到... 应该默认是选上了)
下面可以开始漫长的内核编译了(最好完整编译一次,直接make就行):
make # 相当于 make bzImage modules
(其间会提示几个警告,忽略之... 只要他还在继续往下编译,就放着不管好了)
make modules_install # 安装编译好的modules
make install # 将bzImage添加到grub中,以便用新内核启动(注意,新添加的内核不是默认启动项)
(用 make install 可以免去手动复制bzImage并生成initrd的繁琐过程,推荐!)
等安装完成(不用重启),然后编译PF_RING自带的程序。首先复制 linux/ring.h 到include中
cd ../.. # 回到 PF_RING/ 下
cp kernel/include/linux/ring.h /usr/include/linux/
cp kernel/include/linux/ring.h /usr/include/ # 有些地方说这里也要复制一个,感觉不需要
编译附带的源码和libpcap:
cd userland
make # 直接在userland下make,会自动编译子目录里的所有文件
安装pf_ring的 lib 和 libpcap-ring:
cd lib/
make install
=*= making library libpfring.so =*=
gcc -shared pfring.o -lpthread -o libpfring.so
cp libpfring.a /usr/local/lib/
cp libpfring.so /usr/local/lib/
cp pfring.h /usr/local/include/
cd ../libpcap-0.9.7-ring/
make install
OK,重启机器选新内核启动,就可以使用PF_RING来抓包了。
注意,刚启动机器时,ls /proc/net/pf_ring/ 是看不到这个目录的,只有当需要PF_RING的程序第一次运行时,才会生成这个目录以及一个info文件。之前因为死活找不到这个目录,还以为自己编的内核有问题又来了一次...
重启后这样测试 PF_RING:
cd /home/kernel/PF_RING/userland/examples
./pfcount # 对应的还有一个 pcount,可以比较丢包率
(注意:运行 pfcount 和 pf_test 需要root权限,不然会提示 pfring_open error)
另外查看dmesg或/var/log/messages,可以看到PF_RING的信息:
# dmesg | grep RING
[PF_RING] Welcome to PF_RING 3.9.3 # 这一部分是PF_RING初始化时输出的
[PF_RING] Ring slots 4096
[PF_RING] Slot version 9
[PF_RING] Capture TX Yes [RX+TX]
[PF_RING] IP Defragment No
[PF_RING] Initialized correctly
[PF_RING] registered /proc/net/pf_ring/
[PF_RING] successfully allocated 815104 bytes at 0xd0ad4000 # 以后每次运行PF_RING程序,会输出这样的调试信息
[PF_RING] allocated 4115 slots [slot_len=198][tot_mem=815104]
[PF_RING] removed /proc/net/pf_ring/2849-eth0.0