昨天解决了tcpcopy的一个小却很重要的bug.

tcpcopy的基础函数有个bug,流量比较大的时候,内核buffer满了。send系统调用发不完用户缓冲中的数据才会出现。然后加入了tcpcopy的QQ群,和作者稍稍讨论了一点时间。问了关于写论文和tc_session.c过于复杂的问题。

(wangb) 10:00:55 
https://github.com//tcpcopy/pull/162
(wangb) 10:01:04 
The bug arises when send system call returns with part of data transfered
and part of data still need to be sent again.
(wangb) 10:01:13 
常见于压力比较大的场合
(wangb) 10:02:14 
当然如果系统参数设置好的话,这样的情况不常见。这也是为啥我这边无法重现的原因所在
(wangb) 10:02:46 
当然昨天在开发gryphon,貌似遇到过一次
(wangb) 10:03:06 
gryphon给的压力,有时候真不是一般快和大
siu1ooooooo(16236914) 10:03:14 
我在tcpcopy上作二次开发。碰到了个bug,最后追踪到了 tc_socket_send函数。
siu1ooooooo(16236914) 10:03:52 
流量比较大的时候,内核buffer满了。send系统调用发不完用户缓冲中的数据才会出现。
siu1ooooooo(16236914) 10:05:21 
希望能贡献更多代码的。。但是tc_session.c这个模拟tcp状态机的代码太难看懂了。
(wangb) 10:05:49 
有些bug,程序员自身很难发现,往往需要依赖于用户的反馈,当然有上面的bug提出,就更好了
tc_session.c这个模拟tcp状态机,其实不仅模拟tcp状态机,而为复杂的是模拟上层应用交互
光模拟tcp状态机,是远远不够的
siu1ooooooo(16236914) 10:07:27 
有个想法, 把TCP的11个标准状态加入到tc_session中。可不可以做的。.
(wangb) 10:09:13 
数据是死的,但测试服务器是活的。应该可以吧,但加入可能会更复杂。tc_session.c这个会进一步改进的,代码需简化和功能需独立,使其易懂
siu1ooooooo(16236914) 10:09:31 
🙂
(wangb) 10:10:33 
2010~2012.5月,初步探索阶段;2012.5~2014.5,为进一步探索阶段 2014.5~以后,进一步优化
因为tcpcopy刚开始,开发人员是无法知道复杂的互联网的各种应用的特性的,只有积累到一定程度,才能进一步优化。与其说是开发,不如说是探索
siu1ooooooo(16236914) 10:12:10 
期待工程paper  
siu1ooooooo(16236914) 10:12:43 
tcpcopy稳定到了一个版本。先别加功能了。写paper吧  
siu1ooooooo(16236914) 10:13:01 
投中EI应该问题不大。
siu1ooooooo(16236914) 10:13:55 
中了paper,贡献者会迅速增多。
wangb() 10:15:43 
其实写过sigcomm论文,但被拒,说应该投USENIX ATC
wangb() 10:16:18 
I don't think that the research contribution of the paper is a good match for Sigcomm. Perhaps it would be a better match for 
a more practice-oriented conference like USENIX ATC. 
siu1ooooooo(16236914) 10:16:50 
后来呢
wangb() 10:17:05 
确实,tcpcopy是基于实践的,从实践中摸索爬行的。后来我就先不写论文了
siu1ooooooo(16236914) 10:17:22 
嗯。这是个工程实践性很强的探索啊
wangb() 10:17:27 
要写论文,必须要有条件
siu1ooooooo(16236914) 10:17:45 
喔。
wangb() 10:18:06 
从交换机或者其它设备。镜像过来,这样测试系统和在线系统就没有关联,这样的论文是能够中USENIX ATC

wangb() 10:19:13 
tcpcopy最高端的应用,就是在交换机,利用分光镜或者其它镜像设备,利用高性能硬件,把用户的请求数据包复制给测试系统,可惜我没有这样的条件
wangb() 10:19:38 
要是有这样的条件,我肯定要写论文了
siu1ooooooo(16236914) 10:19:55 
呃。。没怎么看懂  
siu1ooooooo(16236914) 10:21:49 
是说复制的流量要非常非常大才能中论文么
siu1ooooooo(16236914) 10:21:59 
而非常大的流量需求硬件支持
wangb() 10:22:02 
twitter梦想的测试环境,其实完全可以用我们的tcpcopy来实现。交换机上面不是有来来往往的数据包吗?在那上面把请求数据包镜像到测试系统,测试系统搭一个跟在线类似的完整系统,这样测试系统跟在线系统承受类似的压力
wangb() 10:22:17 
高端大气,才能中论文
wangb() 10:22:48 
屌丝环境,写论文,还不被批啊
siu1ooooooo(16236914) 10:23:14 
呃。是 。。。明白了。。想起以前学校的事情,懂了。
wangb() 10:24:38 
总之,tcpcopy值得你去研究,期望有更多接班人把思想传承下去,代码可以推掉重来
wangb() 10:25:10 
只要tcp协议还存在,这个思想,应该是最先进的,无法再先进了
siu1ooooooo(16236914) 10:26:11 
需要好多的开发时间啊。..嗯。先上班了啊。多谢wangbin….
wangb() 10:27:16 
慢慢来,这方面反正国外没有人做

copyright blog.ykyi.net

tcpcopy在视频广告组的二次开发

1.

流量筛选中的 “只导入某频道的流量”功能已经实现了。

技术层面上,实际上是通过指定正则式的方法匹配HTTP请求中的GET方法中的URL来达到过滤的目的。

所以,也可以用ty,ad_type, pf, coverid, oadid, v,plugin等出现在GET方法中的参数编写正则式来过滤流量。

 

2.

流量筛选中的“地域纬度筛选”暂时没有实现。

因为地域纬度的信息不是以参数形式出现在GET方法的URL中,需要通过IP地址或者cookie的中QQ号信息来判断。

还没最终决定是否实现这个功能。

 

3.

tcpcopy官方版本主要的应用场景是复制实时流量。所以部署的时候至少两台机器,一台线上机,另一台测试用机。为了方便压力测试,还引入了至少三台机器的高级模式。

部署起来比较麻烦。

如果“视频CPM广告的模拟投放,以及订单效果预估“只是从磁盘中读入以往的流量,针对这种场景,可以探索tcpcopy的单机离线模式,做到方便部署和使用。

 

4. 部分同学有一个误解.

"将线上的实际访问流量,复制一份保存到本地服务器,用于后续使用"

目前,tcpcopy的官方的版本没有把流量保存下来的功能,保存流量这个目前是用tcpdump的-w选项来做的。

 

另外,技术上,tcpdump只能在IP层和TCP层指定过滤条件,不能用业务的逻辑过滤流量。第1点提到的流量筛选工作在tcpcopy读入实时流量时,或者从tcpdump存下的文件中读入流量时,在应用层指定过滤条件。

copyright blog.ykyi.net

用线上机测试tcpcopy基本通过。支持旧模式,Advanced模式失败

测试结果介绍:

 

tcpcopy在编译期配置成使用NFQueue模式,用Raw Socket抓包。线上机的流量被成功复制并导向测试机。经改动的tcpd初期工作正常。

改动版的tcpd(实际上是一个echo服务器)。测试机上的tcpd把收到的报文被打印到日志文件。但日志文件到6M+大小的时候,就停止打印。目前还没有查到原因,可能是改动后的tcpdBug。此时,tcpdump仍然抓到大量从线上机复制来的真实流量到达测试机。tcpcopy应该是工作正常的。

 

tcpcopy被编译成使用libpcap抓包时不能在线上机上正常工作。tcpdump没有抓到预期从线上机复制到测试机的报文。原因是:线上机10.130.68.100上的真实流量从网络接口tunl0:0进入,从网络接口eth1发出。分析tcpd的日志发现,tcpd使用libpcap只拿到tunl0IP,没有发现tunl0:0IP。需要了解IP隧道,和libpcap库的相关知识,有可能解决这个问题。

 

编译成使用Raw Socket抓包,和Advanced模式时,tcpcopy启动失败,错误日志显示Advanced模式只能使用libpcap库抓包。因此,只有在解决libpcap正确识别tunl0:0网络接口后,才能在线上机上运行tcpcopy

 

预备知识:

Tcpcopy可以编译成用libpcap抓包或者使用Raw Socket抓包。Libpcap库是tcpdump使用的抓包库,Raw Socket是操作系统内建的功能。

官方文档建议用libpcap抓包,以获得更高性能和较低丢包率。

 

Tcpcopy在编译期指定工作模式。tcpcopy目前有两种工作模式,一种使用IPQueue技术或者NFQueue技术。NFQueue技术是用来替代IPQueue技术的。我们目前使用的tlinux,内建了NFQueue内核模块,没有开启IPQueue模块。因为NFQueue是内建的即CONF_XXXXXX = y,而不是编译成模块,即CONF_XXXXX = m, 所以我们在环境中不需要使用modprobe 加载IPQueue或者NFQueue模块。忽略官方文档中提到的modprobe ip_queue

 

测试步骤:

 

使用NFQueue模式:

线上机:10.130.68.100

编译tcpcopy时指定使用NFQueue不要指定 –enable-pcap,则默认使用raw socket抓包。用pcap抓包时识别不到网络接口tunl0:0,而tunl0:0是真实流量的入口。

# ./configure –enable-nfqueue

#./make

生成的tcpcopysrc/tcpcopy 目录下。

运行tcpcopy命令,把流量复制到测试机:

# ./tcpcopy -x 80-10.213.243.156

测试机:10.213.243.156

编译tcpcopy时同样指定–enable-nfqueue,不要指定–enable-pcap。然后运行intercept

# ./intercept

 

使用Advanced模式:

因为暂时未能解决用libpcap识别到网络设备tunel0:0的问题,实际上Advanced模式暂时不能工作。根据以前的使用经验,用Advanced模式时需要注意两点:

1. ./configure时指定 –enable-advaned –enable-pcap

2. Advanced模式需要两台测试机,需要设成一条路由把复制后的真实流量导向测试机。需要更改默认路由:删掉当前的默认路由,新的默认路由从正确的网卡指向测试机2IP

# route del default

# route add default gw 10.213.243.156 dev eth1

copyright blog.ykyi.net

Tcpcopy初体验.

Tcpcopy 初体验

 

Tcpcopy是一个模拟真实流量的测试工具。它的工作基本思想是,从已经上线的服务器复制一份真实流量到测试服务器。Tcpcopy的代码开源,代码仓库放在https://github.com/wangbin579/tcpcopy

 

经过初步学习,已成功在公司的测试机器上部署tcpcopy,并用简单的DEMO程序测试达到预期目的。

 

1.安装

因为作者写的安装介绍只提到最基本的信息,而测试环境各不一样,在我用的测试机的实际安装过程中碰到一些问题。这时问题在这里列出,以供后来者参考,以节省时间。测试机:10.12.194.199 ; 10.12.194.212 ; 10.12.194.214 。

 

1.1 需要额外安装的库:

需要在网站 www.netfilter.org 下载 libmnl, libnfnetlink, libnetfilter_queue 三个工程并安装。 安装顺序为 libmnl, libnfnetlink, libnetfilter_queue,因为第三个依赖第二个,第二个依赖第一个。安装方法是GNU工具的传统三板斧方式: ./configure ; make; make install。这三个工程生成三个.so库放置到/usr/local/lib,而我们用的操作系统环境并没有把该目录列在默认查找库文件的目录列表中,因此要编辑 /etc/ld.so.conf 文件,把目录/usr/local/lib 加入,再运行 ldconfig 更新ld链接程序使用的cache。

 

1.2 IP_Queue和NFQueue内核模块:

这两个内核模块给在用户空间编写处理内核空间中传递网络数据包提供接口。它们的区别是IP_Queue是旧的实现,仅支持IPv4,NFQueue是新的实现。Tcpcopy工程依赖这两个模块之一。

 

Tcpcopy官方文档中多次提到tcpcopy在内核版本小于3.5时默认使用IP_Queue,并在使用例子中有一步操作:

# modprobe ip_queue

这个操作是确保加载ip_queue模块到内核。

我们的测试环境的内核版本号是2.6.32,按照官方文档介绍,内核版本小于3.5,于是使用#modprobe ip_queue命令,结果报错显示我们使用的内核没有启用动态模块加载。

于是再用 # zcat /proc/config.gz 检查当前内核的配置,发现CONFIG_IP_NF_QUEUE is not set, 说明IP_Queue模块没有被buit-in,再查找NFQueue的配置项发现 CONFIG_NETFILTER_NETLINK_QUEUE=y。

所以,在我们的环境中,应该忽略官方文档中# modprobe ip_queue,我们的内核已经内建了比IPQueue更新的NFQueue

 

1.3 编译安装tcpcopy

官方文档中把已经正常运行业务的服务器称为在线服务器(online server),把运行待测试用的服务器称为目标服务器(target server)。

在在线服务器端运行配置命令时务必指定 –enable-nfqueue,这是因为我们用的内核中只有NFQueue,如果不指定这个选项,编译出的tcpcopy不会运行成功,会在日志文件中报错:please make sure ip queue is running.

# ./configure –enable-nfqueue –enable-pcap

 

官方文档中介绍设置防火墙规则时写道,如果内核使用NFQueue,则在目标服务器如此设置

# iptables -I OUTPUT -p tcp –sport port -j NFQUEUE

实际执行中,iptables返回出错iptables: Unknown error 18446744073709551615。咨询万能的谷歌后,给的答案是iptables的版本太旧,不认识NFQueue。于是下载了新的iptables版本并安装,但编译时报错缺少一个库文件,这个新的库文件在我们的相对比较旧的环境下没有。解决方案是仍然用旧的iptables:

# iptables -I OUTPUT -p tcp –sport port -j QUEUE

没有使用NFQUEUE,而是使用QUEUE,iptables设定通过。后面的测试证明暂时也没有问题。

 

2.测试

我把tcpd稍微改了一下,改成了一个echo服务器同时也打印收到的报文,监听9999端口。

把10.12.194.199作为在线服务器:

 

# cd /home/kamus/bin

# ./tcpd                  # 运行echo服务器

# ./tcpcopy -x 9999-10.12.194.212:9999  # 把发往echo服务器的tcp包复制一份发往10.12.194.212的9999端口

# ./tcpdump -vv -i any dst port 9999 # 监视所有发往9999端口的包

 

把 10.12.194.212 作为目标服务器:

# cd /home/kamus/bin

# ./tcpd

# ./intercept

 

把 10.12.194.214 作为客户机:

# cat /etc/passwd | netcat 10.12.194.199 9999

客户机把本机的密码文件发往10.12.194.199机器的echo服务器。这时客户机,在线服务器和目标服务器都打印出了 /etc/passwd 的文件。运行在在线服务器上的tcpdump监控到了tcpcopy复制的包。测试结果符合预期。

 

3.小结

目前只是简单的实验了一下tcpcopy,没有进行大流量的测试。

 

Tcpcopy的官方首页上的文档比用git clone下载下来后的源代码树中的最新文档旧。新的tcpcopy实现有了更高级的发式,可以不依赖内核空间的IP_Queue或NFQueue模块,但需要额外一台机器。还未测试这种方式。

 

另外,我有个想法,如果在线服务器和目标服务器用集线器连接,那么理论上可以在目标服务器上嗅探到在线服务器上收发的数据包,这样就可以不用在在线服务器上运行tcpcopy复制流量,而只需要在目标服务器上嗅探以太网上发往在线服务器上的数据包,这样就会对在线服务器毫无影响。

 

大致看了下tcpcopy的代码,发现代码写得很干净,希望把tcpcopy的代码详细看一遍,以后就能在上面进行二次开发,以及提高调试使用tcpcopy时出错的能力。

copyright blog.ykyi.net