systemtap的網路監控指令碼

myownstars發表於2013-05-25

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=="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("
{
printf ("%s -> %s\n", thread_indent(1), ppfunc())
}
probe kernel.function("
{
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/,如需轉載,請註明出處,否則將追究法律責任。

相關文章