カーネルモジュールことはじめ #9

だいぶ間があいてしまいましたが、気を取り直して再開します。「カーネルモジュールことはじめ」といいつつIPVSに偏ったネタばかりですが気にせずに進めます。今日は、こないだ書いたコード を見ながらIPVSの挙動を少しだけ追ってみたいと思います。

IPVSに新しいスケジューラを登録するには、module_init() で指定した初期化関数の中で、register_ip_vs_scheduler() を使います。登録用のエントリとして利用する ip_vs_scheduler 構造体は、include/net/ip_vs.h で以下のように定義されています。

/*
 *  The scheduler object
 */
struct ip_vs_scheduler {
  struct list_head  n_list;   /* d-linked list head */
  char      *name;    /* scheduler name */
  atomic_t    refcnt;   /* reference counter */
  struct module   *module;  /* THIS_MODULE/NULL */

  /* scheduler initializing service */
  int (*init_service)(struct ip_vs_service *svc);
  /* scheduling service finish */
  int (*done_service)(struct ip_vs_service *svc);
  /* scheduler updating service */
  int (*update_service)(struct ip_vs_service *svc);

  /* selecting a server from the given service */
  struct ip_vs_dest* (*schedule)(struct ip_vs_service *svc,
               const struct sk_buff *skb);
};

この構造体では、以下のメンバに関数ポインタを指定します。

  • init_service
  • done_service
  • update_service
  • schedule

今回は、これらの関数がどのタイミングで実行されるのかを調べてみます。こないだ書いたコードでは、それぞれの関数の中から IP_VS_DBG() を呼んでいます。これは、/proc/sys/net/ipv4/vs/debug_level で指定されたデバッグレベル未満のメッセージをカーネルログに出力するものです。ここでは、IP_VS_DBG(7,"") としているので、デバッグレベルを 8に設定します。

# sysctl -w net.ipv4.vs.debug_level=8

そして、ログを眺めながら以下の操作をやってみます

  • モジュールをロード
  • 仮想サービスを追加
  • リアルサーバを追加
  • 仮想サービスへ接続
  • リアルサーバを削除
  • 仮想サービスを削除
# modprobe ip_vs_test
# ipvsadm -A -t 10.0.0.1:80 -s test
kernel: IPVS: ip_vs_sched_getbyname(): sched_name "test"
kernel: IPVS: ip_vs_test: init_svc

# ipvsadm -a -t 10.0.0.1:80 -r 192.168.0.1:80
kernel: Enter: ip_vs_add_dest, net/ipv4/ipvs/ip_vs_ctl.c line 780
kernel: Enter: ip_vs_new_dest, net/ipv4/ipvs/ip_vs_ctl.c line 732
kernel: Leave: ip_vs_new_dest, net/ipv4/ipvs/ip_vs_ctl.c line 764
kernel: IPVS: ip_vs_test: update_svc
kernel: Leave: ip_vs_add_dest, net/ipv4/ipvs/ip_vs_ctl.c line 869

# telnet 10.0.0.1 80
kernel: IPVS: Bind-dest TCP c:10.211.55.5:2892 v:10.0.0.1:80 d:192.168.0.1:80 fwd:R s:0 conn->flags:183 conn->refcnt:1 dest->refcnt:2
kernel: IPVS: Schedule fwd:R c:10.211.55.5:2892 v:10.0.0.1:80 d:192.168.0.1:80 conn->flags:1C3 conn->refcnt:2
kernel: IPVS: TCP input  [S...] 192.168.0.1:80->10.211.55.5:2892 state: NONE->SYN_RECV conn->refcnt:2
kernel: IPVS: Unbind-dest TCP c:10.211.55.5:2892 v:10.0.0.1:80 d:192.168.0.1:80 fwd:R s:3 conn->flags:183 conn->refcnt:1 dest->refcnt:2

# ipvsadm -d -t 10.0.0.1:80 -r 192.168.0.1:80
kernel: Enter: ip_vs_del_dest, net/ipv4/ipvs/ip_vs_ctl.c line 997
kernel: IPVS: ip_vs_test: update_svc
kernel: Leave: ip_vs_del_dest, net/ipv4/ipvs/ip_vs_ctl.c line 1024

# ipvsadm -D -t 10.0.0.1:80
kernel: IPVS: ip_vs_test: done_svc

今日のまとめ

init_service

仮想サービスを追加するときに呼び出されます(ipvsadm -A)

done_service

仮想サービスを削除するときに呼び出されます(ipvsadm -D)

update_service

リアルサーバを追加するときに呼び出されます(ipvsadm -a)
リアルサーバを削除するときに呼び出されます(ipvsadm -d)

schedule

仮想サービスへ接続されたときに呼び出されます