ネットワーク
今回はDTraceを使ってネットワーク関係のデータを集計するサンプルを紹介します。たとえば、次のようにdtrace(8)を実行すると受信したパケットを送信元のIPアドレスごとに集計して表示してくれます。
図 受信したIPパケットを送信元アドレス毎に集計
# dtrace -n 'ip:::receive{@[args[2]->ip_saddr]=count()}'
dtrace: description 'ip:::receive' matched 1 probe
^C
192.168.185.2 4
216.58.197.228 5
172.217.27.67 13
96.47.72.132 53
192.168.185.1 612
#
先ほどのサンプルはプローブip:::receiveを指定してデータを集計していますが、これをip:::sendにして、今度は送信先アドレスごとにパケットのデータ長のデータを集めてグラフにまとめると次のような結果が得られます。
図 送信パケットデータ長の分散グラフ
# dtrace -n 'ip:::send{@[args[2]->ip_daddr]=quantize(args[2]->ip_plength)}'
dtrace: description 'ip:::send' matched 1 probe
^C
216.58.220.227
value ------------- Distribution ------------- count
8 | 0
16 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 7
32 |@@@@ 1
64 |@@@@ 1
128 | 0
192.168.185.2
value ------------- Distribution ------------- count
16 | 0
32 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 11
64 | 0
216.58.197.227
value ------------- Distribution ------------- count
8 | 0
16 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 14
32 |@@@@ 2
64 |@@@@ 2
128 | 0
96.47.72.132
value ------------- Distribution ------------- count
8 | 0
16 |@@@@@@@@@@@@@@@ 16
32 |@@@@@@@@@@@@@@ 15
64 |@@@@@@ 6
128 | 0
256 |@@ 2
512 |@ 1
1024 |@@ 2
2048 | 0
192.168.185.1
value ------------- Distribution ------------- count
16 | 0
32 |@ 11
64 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 460
128 |@@ 31
256 | 3
512 | 4
1024 | 5
2048 | 3
4096 | 3
8192 | 0
#
これで目的地へのパケットのデータ長の様子がわかります。こんな感じでデータ長をチェックすると、たとえばジャンボフレームが使われることを想定している経路なのにジャンボフレームが使われていないとか、表示されるサイズを調べることでそういったことを検出できます。
今度はip:::receiveとip:::sendの双方を使ってやり取りの状況をモニタリングするスクリプトを取り上げます。
リスト ipio.d
#!/usr/sbin/dtrace -s
#pragma D option quiet
#pragma D option switchrate=10hz
dtrace:::BEGIN
{
printf(" %3s %10s %15s %15s %8s %6s\n", "CPU", "DELTA(us)",
"SOURCE", "DEST", "INT", "BYTES");
last = timestamp;
}
ip:::send
{
this->delta = (timestamp - last) / 1000;
printf(" %3d %10d %15s -> %15s %8s %6d\n", cpu, this->delta,
args[2]->ip_saddr, args[2]->ip_daddr, args[3]->if_name,
args[2]->ip_plength);
last = timestamp;
}
ip:::receive
{
this->delta = (timestamp - last) / 1000;
printf(" %3d %10d %15s delta,
args[2]->ip_daddr, args[2]->ip_saddr, args[3]->if_name,
args[2]->ip_plength);
last = timestamp;
}
これを実行すると次のような結果が得られます。こんな出力が簡単に得られるところがDTraceのすごいところです。
図 ipio.dの実行結果
# ./ipio.d
CPU DELTA(us) SOURCE DEST INT BYTES
2 674 192.168.1.101 -> 192.168.1.39 bge0 140
1 4757 192.168.1.101 192.168.1.39 bge0 156
2 13 192.168.1.101 -> 192.168.1.39 bge0 124
1 2788 192.168.1.101 192.168.1.39 bge0 220
2 13 192.168.1.101 -> 192.168.1.39 bge0 124
1 4551 192.168.1.101 192.168.1.39 bge0 204
2 12 192.168.1.101 -> 192.168.1.39 bge0 140
1 1893 192.168.1.101 192.168.1.39 bge0 252
2 13 192.168.1.101 -> 192.168.1.39 bge0 84
1 3389 192.168.1.101 192.168.1.39 bge0 244
2 12 192.168.1.101 -> 192.168.1.39 bge0 100
1 44157 192.168.1.101 192.168.1.39 bge0 244
3 12 192.168.1.101 -> 192.168.1.39 bge0 100
1 2790 192.168.1.101 192.168.1.39 bge0 236
3 13 192.168.1.101 -> 192.168.1.39 bge0 108
1 3684 192.168.1.101 192.168.1.39 bge0 220
3 12 192.168.1.101 -> 192.168.1.39 bge0 124
1 2178 192.168.1.101
同じくip:::receiveとip:::sendを使ってデータを集計して出力するスクリプトを紹介します。こちらは先ほどと違ってCtrl-Cが押されるまでのデータをため込んで、Ctrl-Cが押されると集計結果を出力します。
リスト ipproto.d
#!/usr/sbin/dtrace -s
dtrace:::BEGIN
{
printf("Tracing... Hit Ctrl-C to end.\n");
}
ip:::send,
ip:::receive
{
this->protostr = args[2]->ip_ver == 4 ?
args[4]->ipv4_protostr : args[5]->ipv6_nextstr;
@num[args[2]->ip_saddr, args[2]->ip_daddr, this->protostr] = count();
}
dtrace:::END
{
printf("\n");
printf(" %-28s %-28s %6s %8s\n", "SADDR", "DADDR", "PROTO", "COUNT");
printa(" %-28s %-28s %6s %@8d\n", @num);
}
実行すると次のような結果が得られます。
図 ipproto.dの実行結果
# ./ipproto.d
dtrace: script './ipproto.d' matched 4 probes
CPU ID FUNCTION:NAME
2 1 :BEGIN Tracing... Hit Ctrl-C to end.
^C
1 2 :END
SADDR DADDR PROTO COUNT
192.168.1.10 192.168.1.101 TCP 1
192.168.1.101 192.168.1.10 TCP 1
192.168.1.101 210.173.160.57 UDP 1
0.0.0.0 255.255.255.255 UDP 2
192.168.1.101 202.216.224.66 UDP 3
192.168.1.39 255.255.255.255 UDP 4
192.168.1.53 224.0.0.22 IGMP 4
192.168.1.101 202.216.246.91 UDP 5
202.216.246.91 192.168.1.101 UDP 5
192.168.1.107 239.255.255.250 UDP 6
192.168.1.106 239.255.255.250 UDP 8
192.168.1.39 192.168.1.255 UDP 8
192.168.1.39 239.255.255.250 UDP 8
192.168.1.107 255.255.255.255 UDP 18
192.168.1.10 192.168.1.255 UDP 26
192.168.1.101 96.47.72.132 TCP 27
96.47.72.132 192.168.1.101 TCP 28
192.168.1.53 224.0.0.251 UDP 32
192.168.1.101 192.168.1.39 TCP 83
192.168.1.39 192.168.1.101 TCP 87
#
従来から提供されている*stat系のコマンドでは特定の通信に関して詳細なデータを取得するといったことを行うのが難しい面がありましたが、DTraceを使うとそういったことを簡単に実現できます。
※ ここに掲載したサンプルスクリプトは"DTrace Dynamic Tracing In Oracle Solaris, Mac OS X & FreeBSD", by Brendan Gregg and Jim Mauro P.440、P.476、P.477より抜粋したものです(一部内容を変更してあるほか、FreeBSDで実行した結果を掲載しています) 。
勉強会
第60回 2月23日(木)19:00~FreeBSD勉強会
発表内容検討中。発表ネタをお持ちの方、ぜひご連絡ください。
参加申請はこちら から。
第61回 3月23日(木)19:00~FreeBSD勉強会:リキャップ・ザ・AsiaBSDCon 2017 ~日本語でふりかえるABC~
2017年3月9~12日まで東京でAsiaBSDCon 2017 が開催される予定です。ぜひこのカンファレンスにご参加いただきたいわけなのですが、なかにはどうしても仕事の都合で参加できなかったとか、正直英語がよくわからなかったとか、そういった方もいらっしゃるのではないかと思います。
3月のFreeBSD勉強会では、AsiaBSDCon 2017のあとというこのタイミングを活かして、AsiaBSDCon 2017の発表内容を振り返ってみよう、というのをやってみようと思います。AsiaBSDConに参加しているにもかかわらず、これまで一度もプロシーディングを読み返したことすらないというあなた、ぜひプロシーディングを持参してご参加ください :) AsiaBSDConに参加できなかったというあなたも、この機会をお見逃しなく(できればAsiaBSDConそのものに参加した方が絶対的によいです、あしからず) 。
FreeBSD勉強会 発表者募集
FreeBSD勉強会では発表者を募集しています。FreeBSDに関して発表を行いたい場合、@daichigoto までメッセージをお願いします。1時間半~2時間ほどの発表資料を作成していただき発表をお願いできればと思います。