技术头条 - 一个快速在微博传播文章的方式     搜索本站
您现在的位置首页 --> 系统运维 --> dropwatch 网络协议栈丢包检查利器

dropwatch 网络协议栈丢包检查利器

浏览:2277次  出处信息

在做网络服务器的时候,会碰到各种各样的网络问题比如说网络超时,通常一般的开发人员对于这种问题最常用的工具当然是tcpdump或者更先进的wireshark来进行抓包分析。通常这个工具能解决大部分的问题,但是比如说wireshark发现丢包,那深层次的原因就很难解释了。这不怪开发人员,要怪就怪linux网络协议栈太深。我们来看下:
network-stack

这7层里面每个层都可能由于各种各样的原因,比如说缓冲区满,包非法等,把包丢掉,这样的问题就需要特殊的工具来发现了。 好了,主角dropwatch出场.
它的官方网站在
这里

What is Dropwatch


Dropwatch is a project I am tinkering with to improve the visibility developers and sysadmins have into the Linux networking stack. Specifically I am aiming to improve our ability to detect and understand packets that get dropped within the stack.


Dropwatch定位很清晰,就是用来查看协议栈丢包的问题。


RHEL系的系统安装相当简单,yum安装下就好:


$ uname -r

2.6.32-131.21.1.tb477.el6.x86_64

$ sudo yum install dropwatch


man dropwatch下就可以得到使用的帮助,dropwatch支持交互模式, 方便随时启动和停止观测。


使用也是很简单:


$ sudo dropwatch -l kas

Initalizing kallsymsa db

dropwatch> start

Enabling monitoring...

Kernel monitoring activated.

Issue Ctrl-C to stop monitoring

1 drops at netlink_unicast+251

15 drops at unix_stream_recvmsg+32a

3 drops at unix_stream_connect+1dc

-l kas的意思是获取drop点的符号信息,这样的话针对源码就可以分析出来丢包的地方。


同学们可以参考这篇文章(Using netstat and dropwatch to observe packet loss on Linux servers):http://prefetch.net/blog/index.php/2011/07/11/using-netstat-and-dropwatch-to-observe-packet-loss-on-linux-servers/


那他的原理是什么呢?在解释原理之前,我们先看下这个工具的对等的stap脚本:


$ cat /usr/share/doc/systemtap-1.6/examples/network/dropwatch.stp

#!/usr/bin/stap


############################################################

# Dropwatch.stp

# Author: Neil Horman <nhorman@redhat.com>

# An example script to mimic the behavior of the dropwatch utility

# http://fedorahosted.org/dropwatch

############################################################


# Array to hold the list of drop points we find

global locations


# Note when we turn the monitor on and off

probe begin { printf("Monitoring for dropped packets ") }

probe end { printf("Stopping dropped packet monitor ") }


# increment a drop counter for every location we drop at

probe kernel.trace("kfree_skb") { locations[$location] <<< 1 }


# Every 1 seconds report our drop locations

probe timer.sec(1)

{

 printf(" ")

 foreach (l in locations-) {

   printf("%d packets dropped at %s ",

          @count(locations[l]), symname(l))

 }

 delete locations

}


这个脚本核心的地方就在于这行:

probe kernel.trace(“kfree_skb”) { locations[$location] <<< 1 }

当kfree_skb被调用的时候,内核就记录下这个drop协议栈的位置,同时透过netlink通知dropwatch用户态的部分收集这个位置,同时把它整理显示出来.以上就是dropwatch的工作流程。


现在的问题是内核什么地方,什么时候会调用kfree_skb这个函数呢? 我们继续追查下:

dropwatch需要对内核打patch,当然RHEL5U4以上的内核都已经打了patch。

patch在这里下载:https://fedorahosted.org/releases/d/r/dropwatch/dropwatch_kernel_patches.tbz2

通过查看里面的5个patch,我们知道drop主要修改了以下几个文件:


include/linux/netlink.h

include/trace/skb.h

net/core/Makefile

net/core/net-traces.c

include/linux/skbuff.h

net/core/datagram.c

include/linux/net_dropmon.h

net/core/drop_monitor.c

include/linux/Kbuild

net/Kconfig

net/core/Makefile


我们透过RHEL5U4的代码可以清楚的看到:


//include/linux/skbuff.h

extern void kfree_skb(struct sk_buff *skb);

extern void consume_skb(struct sk_buff *skb);

这些patch的作用是使得支持dropwatch的内核把kfree_skb分成二类: 1. 人畜无害的调用consume_skb 2. 需要丢包的调用kfree_skb 同时提供基础的netlink通信往用户空间传递位置信息。


知道了这点,我们在RHEL 5U4的源码目录下: linux-2.6.18.x86_64/net/ipv4 或者 linux-2.6.18.x86_64/net/core下 grep下


$ grep -rin kfree_skb  .

./tcp_input.c:3122:                     __kfree_skb(skb);

./tcp_input.c:3219:                     __kfree_skb(skb);

./tcp_input.c:3234:             __kfree_skb(skb);

./tcp_input.c:3318:                             __kfree_skb(skb);

...

./ip_fragment.c:166:static __inline__ void frag_kfree_skb(struct sk_buff *skb, int *work)

./ip_fragment.c:171:    kfree_skb(skb);

./ip_fragment.c:211:            frag_kfree_skb(fp, work);

./ip_fragment.c:452:            frag_kfree_skb(fp, NULL);

./ip_fragment.c:578:                    frag_kfree_skb(free_it, NULL);

./ip_fragment.c:607:    kfree_skb(skb);

./ip_fragment.c:732:    kfree_skb(skb);

./udp.c:1028:   kfree_skb(skb);

./udp.c:1049:           kfree_skb(skb);

./udp.c:1069:                   kfree_skb(skb);

./udp.c:1083:                   kfree_skb(skb);

./udp.c:1134:                                   kfree_skb(skb1);

./udp.c:1229:   kfree_skb(skb);

./udp.c:1242:   kfree_skb(skb);

./udp.c:1258:   kfree_skb(skb);

./udp.c:1418:                           kfree_skb(skb);

./ip_sockglue.c:286:            kfree_skb(skb);

./ip_sockglue.c:322:            kfree_skb(skb);

./ip_sockglue.c:398:    kfree_skb(skb);

./devinet.c:1140:               kfree_skb(skb);

./xfrm4_ninput.c:29:    kfree_skb(skb);

./xfrm4_ninput.c:122:   kfree_skb(skb);

./tunnel4.c:85: kfree_skb(skb);

./icmp.c:47: *                                  and moved all kfree_skb() up to

./icmp.c:1046:  kfree_skb(skb);

./ip_forward.c:121:     kfree_skb(skb);

./netfilter.c:73:               kfree_skb(*pskb);

./netfilter.c:114:              kfree_skb(*pskb);

./netfilter/ip_queue.c:277:             kfree_skb(skb);

./netfilter/ip_queue.c:335:     kfree_skb(nskb);

./netfilter/ip_queue.c:373:                     kfree_skb(e->skb);

./netfilter/ip_queue.c:556:             kfree_skb(skb);

...

./netfilter/ipt_TCPMSS.c:153:           kfree_skb(*pskb);

./netfilter/ipt_ULOG.c:435:                     kfree_skb(ub->skb);

./tcp.c:1458:                           kfree_skb(skb);

./tcp.c:1577:           __kfree_skb(skb);

./ip_gre.c:482:         kfree_skb(skb2);

./ip_gre.c:497:                 kfree_skb(skb2);

./ip_gre.c:504:                 kfree_skb(skb2);

...

./ip_gre.c:892: dev_kfree_skb(skb);

./raw.c:244:            kfree_skb(skb);

./raw.c:254:            kfree_skb(skb);

./raw.c:329:    kfree_skb(skb);

./tcp_ipv4.c:1039:      kfree_skb(skb);

./tcp_ipv4.c:1151:      kfree_skb(skb);

./ipvs/ip_vs_xmit.c:213:        kfree_skb(skb);

./ipvs/ip_vs_xmit.c:290:        kfree_skb(skb);

./ipvs/ip_vs_xmit.c:374:                        kfree_skb(skb);

./ipvs/ip_vs_xmit.c:378:                kfree_skb(skb);

./ipvs/ip_vs_xmit.c:423:        kfree_skb(skb);

./ipvs/ip_vs_xmit.c:480:        kfree_skb(skb);

./ipvs/ip_vs_xmit.c:553:        dev_kfree_skb(skb);

./ipvs/ip_vs_core.c:197:        kfree_skb(*pskb);

./ipvs/ip_vs_core.c:829:        kfree_skb(*pskb);

./ipconfig.c:504:       kfree_skb(skb);

./ipconfig.c:1019:      kfree_skb(skb);

./xfrm4_input.c:50:     kfree_skb(skb);

./xfrm4_input.c:162:    kfree_skb(skb);

./fib_semantics.c:292:          kfree_skb(skb);

./ipip.c:414:           kfree_skb(skb2);

./ipip.c:429:                   kfree_skb(skb2);

./ipip.c:436:                   kfree_skb(skb2);

./ipip.c:444:                   kfree_skb(skb2);

./ipip.c:458:   kfree_skb(skb2);

./ipip.c:482:                   kfree_skb(skb);

./ipip.c:609:                   dev_kfree_skb(skb);

./ipip.c:615:           dev_kfree_skb(skb);

./ipip.c:654:   dev_kfree_skb(skb);

./ipmr.c:185:   kfree_skb(skb);

...

./ip_output.c:763:      kfree_skb(skb);

./ip_output.c:964:                              kfree_skb(skb);

./ip_output.c:1313:             kfree_skb(skb);

我们可以看到一堆可以丢包的点。

当我们观察到dropwatch发现丢包的时候,可以根据符号信息结合以上的源码轻松的分析出来问题所在。


小结: 工具是知识的积累。


建议继续学习:

  1. 记一次丢包网络故障    (阅读:5161)
  2. 网络丢包率如何解决    (阅读:3971)
  3. 在 Linux 的应用中测试中的延时和丢包模拟    (阅读:3323)
  4. 网络方面一些经验    (阅读:3039)
QQ技术交流群:445447336,欢迎加入!
扫一扫订阅我的微信号:IT技术博客大学习
© 2009 - 2024 by blogread.cn 微博:@IT技术博客大学习

京ICP备15002552号-1