stap自带的与网络相关的probe如下,可用于检测一系列网络活动
netdev.close/open--关闭打开设备时调用;dev_name--涉及的设备名
netdev.receive--从网络设备接收的数据;参数:protocl--数据包的协议;dev_name--设备名,诸如eth0;length--接收buffer的长度
netdev.rx--当设备即将接收数据包时调用;参数:protocol--数据包协议;dev_name--接收的设备名
netdev.transmit--发送数据的网络设备;protocol/dev_name/length/truesize--传送的数据大小
socket.aio_read--通过sock_aio_read接收信息时调用;size信息大小type套接字类型protocol协议名
socket.aio_write--通过sock_aio_write发送信息时调用;size信息大小type套接字类型protocol协议名
socket.create--创建套接字;type套接字类型protocol协议名
socket.receive--套接字接收信息;success发送是否成功1失败0size信息大小type套接字类型protocol协议名
socket.send--发送信息;success发送是否成功1失败0size信息大小type套接字类型protocol协议名
socket.sendmsg--正在发送信息的套接字;
tcp.disconnect--退出TCP连接;dport/sport目标/源端口;saddr/daddr源IP/目标IP;
tcp.disconnect.return
tcp.receive--接收TCP包;protocol协议名dport/sport/saddr/daddr/ack/fin/syn
tcp.recvmsg--正在接收TCP信息;
tcp.sendmsg--正在发送TCP信息;
netfilter.ip.local_in--Called on an incoming IP packet addressed to the local computer
netfilter.ip.local_out-- Called on an outgoing IP packet
netfilter.ip.forward - Called on an incoming IP packet addressed to some other computer
例1
network/netfilter_drop.stp
丢弃接收的TCP/UDP前N个包
# stap -g netfilter_drop.stp TCP 1 -c "sleep 2"
#! /usr/bin/env stap
global drop_count
#将网络协议从数字转换为等义字符串,6=TCP 17=UDP
function convert_protocol(proto_n) {
proto_s="Other"
if (proto_n==6)
proto_s="TCP"
else if(proto_n==17)
proto_s="UDP"
return proto_s
}
probe netfilter.ipv4.local_in {
#传入参数length--包长度 nf_stop--将此包定义为stop, verdict--该包最终处理决定
if(convert_protocol(protocol) ==@1 || @1=="ALL") {
if(@count(drop_count[@1])>=$2 && $2 !=0)
exit()
else {
$verdict=nf_stop
drop_count[@1]<< #使用聚集数组,可同时对其执行count/sum操作
}
}
}
probe begin {
#判断参数1参数2是否符合标准
if (@1 !='TCP' || @1 !='UDP' && @1 !='ALL') || ($2<0) {
printf("Please enter \"TCP\", \"UDP\" or \"ALL\" on the command line, followed by the number of packets to drop.\n")
exit()
}
else
printf("Dropping packets! Ctrl+C to stop")
}
probe end{
foreach(proto in drop_count)
printf("%d %s packets drop, total %d bytes\n",@count(drop_count[proto]),proto,@sum(drop_count[proto]))
}
例2
在后台运行,将内核的tcp cwnd覆盖为10,用于改善web server的延迟
#! /usr/bin/stap -g
probe kernel.function("tcp_init_cwnd").return {
r = $return
if( r>0 && r<10)
$return =10;
counts[r,$return] <<< 1
}
global counts # will be automatically summarized at shutdown
该脚本起始于http://blog.yufeng.info/archives/1173
tcp_init_cwnd.stp
probe kernel.function("tcp_init_cwnd").return
{
$return = $1
}
#设成7个mss
$ sudo stap -p4 -g -m initcwnd tcp_init_cwnd.stp 7
initcwnd.ko
加载到远端机器
$ sudo insmod initcwnd.ko
例3
network/netdev.stp
跟踪网卡活动,提交和接收包以及更改配置
#! /usr/bin/env stap
probe netdev.get_stats ? {
printf("%s was asked for stats structure\n", dev)
}
probe netdev.register {
printf("registering netdev_name\n",dev_name)
}
probe netdev.unregister{
printf("unregistering netdev_name\n",dev_name)
}
probe netdev.ioctl{
printf("netdev ioctl raised with param:%d and arg:%s\n",cmd,arg)
}
probe netdev.set_promiscuity {
if (enable)
printf("Device %s entering in promiscuous mode\n", dev_name)
else
printf("Device %s leaving promiscuous mode\n", dev_name)
}
probe netdev.change_rx_flag ? {
printf("Device %s is changing its RX flags to %d\n", dev_name, flags)
}
probe netdev.change_mtu {
printf("Changing MTU on device %s from %d to %d\n", dev_name,
old_mtu, new_mtu)
}
probe netdev.change_mac {
printf("Changing MAC address on device %s from %s to %s\n",
dev_name, old_mac, new_mac)
}
probe netdev.transmit {
printf("Device %s is sending (queued) a packet with protocol %d\n", dev_name, protocol)
}
probe netdev.hard_transmit {
printf("Device %s is sending (hard) a packet with protocol %d\n", dev_name, protocol)
}
probe netdev.rx {
printf("Device %s received a packet with protocol %d\n", dev_name, protocol)
}
例4
nettop.stp
按照网络接收或发送次数降序排列,每5秒打印一次
global ifxmit,ifrecv
global ifmerged
probe netdev.transmit {
ifxmit[pid(),dev_name,execname(),uid()] <<< length --将发送的包长度存放到ifxmit
}
probe netdev.receive {
ifrecv[pid(),dev_name,execname(),uid()] <<< length --将接受的包长度存放到ifrecv
}
function print_activity {
printf("%5s %5s %-7s %7s %7s %7s %7s %-15s\n",
"PID", "UID", "DEV", "XMIT_PK", "RECV_PK",
"XMIT_KB", "RECV_KB", "COMMAND")
foreach ([pid,dev,exec,uid] in ifxmit) {--遍历ifxmit,计算相同属性进程发送和接受包的总次数
ifmerged[pid,dev,exec,uid] += @count(ifxmit[pid,dev,exec,uid]);
}
foreach ([pid,dev,exec,uid] in ifrecv) {
ifmerge[pid,dev,exec,uid] += @count(ifrecv[pid,dev,exec,uid]);
}
foreach ([pid,dev,exec,uid] in ifmerge -) {--按发送+接收次数降序排列
n_xmit = @count(ifxmit[pid,dev,exec,uid]);--发送次数
n_recv = @count(ifrecv[pid,dev,exec,uid]);--接收次数
printf("%5d %5d %-7s %7d %7d %7d %7d %-15s\n",
pid, uid, dev, n_xmit, n_recv,
n_xmit ? @sum(ifxmit[pid, dev, exec, uid])/1024 : 0,
n_recv ? @sum(ifrecv[pid, dev, exec, uid])/1024 : 0,
exec)
}
delete ifmerged
delete ifxmit
delete ifrecv
}
probe timer,ms(5000), end, error {
print_activity()
}
以下为输出
PID UID DEV XMIT_PK RECV_PK XMIT_KB RECV_KB COMMAND
2886 4 eth0 79 0 5 0 cups-polld
11362 0 eth0 0 61 0 5 firefox
0 0 eth0 3 32 0 3 swapper
2886 4 lo 4 4 0 0 cups-polld
11178 0 eth0 3 0 0 0 synergyc
PID UID DEV XMIT_PK RECV_PK XMIT_KB RECV_KB COMMAND
0 0 eth0 0 6 0 0 swapper
2886 4 lo 2 2 0 0 cups-polld
11178 0 eth0 3 0 0 0 synergyc
3611 0 eth0 0 1 0 0 Xorg
例5
socket-trace.stp
跟踪有关net/socket.c的内核调用
#! /usr/bin/env stap
probe kernel.function("*@net/socket.c").call {
printf ("%s -> %s\n", thread_indent(1), ppfunc())
}
probe kernel.function("*@net/socket.c").return {
printf ("%s }
输出如下
0 Xorg(3611): -> sock_poll
3 Xorg(3611): 0 Xorg(3611): -> sock_poll
3 Xorg(3611): 0 gnome-terminal(11106): -> sock_poll
5 gnome-terminal(11106): 0 scim-bridge(3883): -> sock_poll
3 scim-bridge(3883): 0 scim-bridge(3883): -> sys_socketcall
4 scim-bridge(3883): -> sys_recv
8 scim-bridge(3883): -> sys_recvfrom
例6
监控接受到的TCP数据包
#! /usr/bin/env stap
// A TCP dump like example
probe begin, timer.s(1) {
printf("-----------------------------------------------------------------\n")
printf(" Source IP Dest IP SPort DPort U A P R S F \n")
printf("-----------------------------------------------------------------\n")
}
probe tcp.receive {
printf(" %15s %15s %5d %5d %d %d %d %d %d %d\n",
saddr, daddr, sport, dport, urg, ack, psh, rst, syn, fin)
}
输出如下
-----------------------------------------------------------------
Source IP Dest IP SPort DPort U A P R S F
-----------------------------------------------------------------
209.85.229.147 10.0.2.15 80 20373 0 1 1 0 0 0
92.122.126.240 10.0.2.15 80 53214 0 1 0 0 1 0
92.122.126.240 10.0.2.15 80 53214 0 1 0 0 0 0
209.85.229.118 10.0.2.15 80 63433 0 1 0 0 1 0
例7
监控内核丢弃的网络包
dropwatch.stp
#! /usr/bin/env stap
global locations
probe begin { printf("Monitoring for dropped packets\n") }
probe end { printf("Stopping dropped packet monitor\n") }
probe kernel.trace("kfree_skb") { locations[$location] <<< 1}
probe timer.sec(5) {
foreach(l in locations-) {
printf("%d packets dropped at %s\n", @count(loactions[l]),symname(l))
}
}
--kfree_skb跟踪内核丢弃网络包,有2个参数:$skb指向被释放的buffer的指针;$location被释放的内核代码位置;
运行stap --all-modules dropwatch.stp
注:如果--all-modules不可用,则symname只会打印出raw地址,此时可以使用/boot/System.map-`uname -r`查看其对应的function
Monitoring for dropped packets
1762 packets dropped at unix_stream_recvmsg
4 packets dropped at tun_do_read
2 packets dropped at nf_hook_slow
例8
监控新建的TCP连接
#! /usr/bin/env stap
probe begin {
printf("%6s %16s %6s %6s %16s\n",
"UID", "CMD", "PID", "PORT", "IP_SOURCE")
}
probe kernel.function("tcp_accept").return?,
kernel.function("inet_csk_accept").return? {
sock = $return
if (sock != 0)
printf("%6d %16s %6d %6d %16s\n", uid(), execname(), pid(),
inet_get_local_port(sock), inet_get_ip_source(sock))
}
输出如下
UID CMD PID PORT IP_SOURCE
0 sshd 3165 22 10.64.0.227
0 sshd 3165 22 10.64.0.227
/usr/share/systemtap/testsuite/systemtap.examples/
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/15480802/viewspace-762002/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/15480802/viewspace-762002/