最近 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