最近 Linux Kernel の TCP 周り(特に backlog 周り)を読んでいます。
コードリーディングだけじゃなくて、手を動かしながら確認したいこともあったので、Systemtap を使って TCP State (SYN_RECV とか SYN_ESTABLISHED とか)を確認する Systemtap スクリプトを書いてみました。
コードリーディングの方はメモしていたら結構な量になったので、また後日整理してから…
%{
#include <net/tcp.h>
#include <linux/skbuff.h>
#include <net/inet_connection_sock.h>
#include <net/inet_timewait_sock.h>
#include <uapi/linux/tcp.h>
%}
function show_tcp_rcv_state_process_return:long(sk:long)
%{
struct sock *sk = (struct sock *)STAP_ARG_sk;
struct inet_sock *inet;
inet = inet_sk(sk);
if (inet->inet_num == 12345) {
STAP_PRINTF("return tcp_rcv_state_process\n");
switch (sk->sk_state) {
case TCP_LISTEN:
STAP_PRINTF("TCP_LISTEN\n");
break;
case TCP_SYN_SENT:
STAP_PRINTF("TCP_SYN_SENT\n");
break;
case TCP_SYN_RECV:
STAP_PRINTF("TCP_SYN_RECV\n");
break;
case TCP_ESTABLISHED:
STAP_PRINTF("TCP_ESTABLISHED\n");
break;
}
}
%}
function show_tcp_rcv_state_process:long(sk:long)
%{
struct sock *sk = (struct sock *)STAP_ARG_sk;
struct inet_sock *inet;
inet = inet_sk(sk);
if (inet->inet_num == 12345) {
STAP_PRINTF("tcp_rcv_state_process\n");
switch (sk->sk_state) {
case TCP_LISTEN:
STAP_PRINTF("TCP_LISTEN\n");
break;
case TCP_SYN_SENT:
STAP_PRINTF("TCP_SYN_SENT\n");
break;
case TCP_SYN_RECV:
STAP_PRINTF("TCP_SYN_RECV\n");
break;
case TCP_ESTABLISHED:
STAP_PRINTF("TCP_ESTABLISHED\n");
break;
}
}
%}
function show_tcp_v4_do_rcv:long(sk:long)
%{
struct sock *sk = (struct sock *)STAP_ARG_sk;
struct inet_sock *inet;
inet = inet_sk(sk);
if (inet->inet_num == 12345) {
STAP_PRINTF("tcp_v4_do_rcv\n");
switch (sk->sk_state) {
case TCP_LISTEN:
STAP_PRINTF("TCP_LISTEN\n");
break;
case TCP_SYN_SENT:
STAP_PRINTF("TCP_SYN_SENT\n");
break;
case TCP_SYN_RECV:
STAP_PRINTF("TCP_SYN_RECV\n");
break;
case TCP_ESTABLISHED:
STAP_PRINTF("TCP_ESTABLISHED\n");
break;
}
}
%}
probe kernel.function("tcp_v4_do_rcv")
{
show_tcp_v4_do_rcv($sk);
}
probe kernel.function("tcp_rcv_state_process")
{
show_tcp_rcv_state_process($sk);
}
probe kernel.function("tcp_rcv_state_process").return
{
show_tcp_rcv_state_process_return($sk);
}
Systemtap の function の中で probe した関数の名前を取得する方法が分からず、冗長なコードになっていますが、目的はこれで達成できます。
tcp_v4_do_rcv()
と tcp_rcv_state_process()
を probe しています。
あとはポート番号12345でプロセスを listen させて動かします。
$ sudo stap -g -v test.stp
$ nc -lvp 12345
$ nc localhost 12345
すると次のような出力を得ることができます。
tcp_v4_do_rcv
TCP_LISTEN
tcp_rcv_state_process
TCP_LISTEN
return tcp_rcv_state_process
TCP_LISTEN
tcp_rcv_state_process
TCP_SYN_RECV
return tcp_rcv_state_process
TCP_ESTABLISHED
tcp_v4_do_rcv
TCP_LISTEN
tcp_rcv_state_process
TCP_LISTEN
return tcp_rcv_state_process
TCP_LISTEN
return tcp_v4_do_rcv
TCP_LISTEN
tcp_rcv_state_process
TCP_SYN_RECV
return tcp_rcv_state_process
TCP_ESTABLISHED