EN JA
HHOOK(9)
HHOOK(9) FreeBSD Kernel Developer's Manual HHOOK(9)

名称

hhook, hhook_head_register, hhook_head_deregister, hhook_head_deregister_lookup, hhook_run_hooks, HHOOKS_RUN_IF, HHOOKS_RUN_LOOKUP_IFヘルパフックフレームワーク

書式

#include < sys/hhook.h>

typedef int
(*hhook_func_t)( int32_t hhook_type, int32_t hhook_id, void *udata, void *ctx_data, void *hdata, struct osd *hosd);

int hhook_head_register( int32_t hhook_type, int32_t hhook_id, struct hhook_head **hhh, uint32_t flags);

int hhook_head_deregister( struct hhook_head *hhh);

int hhook_head_deregister_lookup( int32_t hhook_type, int32_t hhook_id);

void hhook_run_hooks( struct hhook_head *hhh, void *ctx_data, struct osd *hosd);

HHOOKS_RUN_IF( hhh, ctx_data, hosd);

HHOOKS_RUN_LOOKUP_IF( hhook_type, hhook_id, ctx_data, hosd);

解説

hhook は、カーネル内で定義されたフックポイントで任意のフック関数を管理して実行するためのフレームワークを提供します。 KPI は、 pfil(9) によって呼び起こされ、多くの点で pfil のより一般的なスーパセットと考えられます。

khelp(9)hhook フレームワークは、密接に統合されています。 Khelp は、 hhook ポイントで Khelp モジュールフック関数の登録と登録取消に対して責任があります。これを行うための khelp(9) によって使用された KPI 関数は、それらがフックポイントのインスタンスを作成したい消費者に関連していないということで、ここで、文書化されていません。

Khelp モジュール開発者のための情報

Khelp モジュールは、フックポイントへの挿入のために適切なフック関数を定義することによって、間接的に hhook と情報をやりとりします。フック関数は、 「書式」 に概説される hhook_func_t 関数ポインタ宣言に適合しなければなりません。

hhook_typehhook_id 引数は、フック関数に呼び出されたフックポイントを識別します。単一のフック関数が複数のフックポイントのために登録され、どのフックポイントがそれに呼び出されたかを知りたいとき、これらは、役に立ちます。利用可能な hhook_type 定義をリストする < sys/hhook.h> とフックポイントをエクスポートするサブシステムは、適切なヘッダファイルで hhook_id 値を定義することに対して責任があります。

udata 引数は、フック登録時に struct hookinfo で指定されたなら、フック関数に渡されます。

ctx_data 引数は、フックポイント呼び出しサイトからのコンテキスト特有のデータを含んでいます。渡されたデータタイプは、サブシステムに依存しています。

hdata 引数は、必要であるなら、モジュールによって使用のために割り付けられた永続的なオブジェクト毎の記憶域へのポインタです。ポインタは、モジュールがオブジェクト毎の記憶域を要求しなかった場合にだけ、つねに NULL となります。

異なった Khelp モジュールに属しているデータにアクセスするために khelp(9) フレームワークの khelp_get_osd() 関数で hosd 引数を使用することができます。

Khelp モジュールは、次のメンバを含むフックポイント毎に struct hookinfo を作成することによって hhook ポイントで、それらのフック関数を登録するための Khelp フレームワークを指示します:

struct hookinfo { 
 hhook_func_t hook_func; 
 struct helper *hook_helper; 
 void  *hook_udata; 
 int32_t  hook_id; 
 int32_t  hook_type; 
};

Khelp モジュールは、Khelp フレームワークによって扱われる hook_helper を除いて、構造体のすべてのメンバを設定することに対して責任があります。

フックポイントの作成と管理

通常、 hhook ポイントを提供したいカーネルサブシステムは、それらの実装への 4 あるいは 5 のキー変更を行う必要があります:
  • 適切なサブシステムヘッダの hhook_id マッピングのリストを定義します。
  • サブシステムの初期化処理の間に hhook_head_register() 関数で各フックポイントを登録します。
  • コンテキスト上のデータとしてフック関数へ渡すために標準化されたデータタイプを選択するか、または作成します。
  • フックポイントが実行されるべきであるサブシステムのコードの時点で HHOOKS_RUN_IF() または HHOOKS_RUN_IF_LOOKUP() への呼び出しを追加します。
  • 実行時に動的にサブシステムを追加するか、または削除できるなら、サブシステムが初期化されたとき、 hhook_head_register() 関数で登録された各フックポイントは、サブシステムが削除の前に初期化が解除されているとき、 hhook_head_deregister() または hhook_head_deregister_lookup() 関数で登録を取り消される必要があります。

hhook_head_register() 関数は、 hhook フレームワークでフックポイントを登録します。 hook_type 引数は、フックポイントのためのハイレベルなタイプを定義します。有効なタイプは、 < sys/hhook.h> で定義され、新しいタイプは、必要に応じて追加されるべきです。 hook_id 引数は、フックポイントのためのユニークなサブシステム特有の識別子を指定します。 hhh 引数は、NULL でないなら、登録プロセスの一部として作成された struct hhook_head への参照を格納するために使用されます。一般的に、サブシステムは、フックポイントのインスタンスを作成するために HHOOKS_RUN_IF() マクロを使用できるように、 struct hhook_head のローカルのコピーを格納したいでしょう。 HHOOK_WAITOK フラグは、 malloc(9) がメモリが利用可能になるのをウェートしてスリープすることが可能になるなら、 flags 引数を通して渡されます。フックポイントが仮想化されたサブシステム (例えば、ネットワークスタック) の中にあるなら、HHOOK_HEADISINVNET は、登録プロセスの間に作成された struct hhook_head が、仮想化されたリストに追加できるように、 flags 引数を通して渡されるべきです。

hhook_head_deregister() 関数は、 hhook フレームワークから以前に登録したフックポイントの登録を取り消します。 hhh 引数は、フックポイントが登録されたとき hhoook_head_register() によって返された struct hhook_head へのポインタです。

呼び出し側が struct hhook_head のキャッシュされたコピーを持たないで、代わりに適切な hook_typehook_id 識別子を使用してフックポイントの登録を取り消すたことが必要な状況で、 hhook_head_deregister() 関数の代わりに hhook_head_deregister_lookup() 関数を使用することができます。

hhook_run_hooks() 関数は、通常、直接呼び出されるべきでなく、代わりに HHOOKS_RUN_IF() マクロを通して間接的に呼び出されるべきです。しかしながら、直接、関数を呼び出すことが望ましい状況があるので、完全性のためにここに文書化されています。 hhh 引数は、すべての登録されたフック関数を呼び出すために hhook ポイントを参照します。 ctx_data 引数は、フック関数に渡すためにコンテキスト上のフックポイントデータへのポインタを指定します。 hosd 引数は、サブシステムがオブジェクト毎のデータを関連づける Khelp モジュールのための能力を提供するなら、適切なオブジェクトの struct osd へのポインタであるべきです。そうしないサブシステムは、NULL を渡すべきです。

HHOOKS_RUN_IF() マクロは、フックポイントを実装する好ましい方法です。少なくとも 1 つのフック関数がフックポイントのために登録される場合にだけ、 hhook_run_hooks() 関数を呼び出します。登録されたフック関数を調べることによって、マクロは、フック関数がない共通の場合のテストが登録されているなら、簡単なものに減少することによって頻繁に使用されたコードのパスにフックポイントを追加することに関連している費用を最小とします。引数は、 hhook_run_hooks() 関数で説明される通りです。

HHOOKS_RUN_IF_LOOKUP() マクロは、 HHOOKS_RUN_IF() マクロと同じ関数をを実行しますが、指定された hook_typehook_id 識別子のために struct hhook_head を検索する追加のステップを実行します。検索に関連している参照カウントのオーバヘッドのために、まれに実行されるコードのパスを除いて、使用されるべきではありません。

実装に関する注

struct hhook_head は、 rmlock(9) でフック関数の内部のリストを保護します。したがって、いつでも、 hhook_run_hooks() は、直接呼び出されるか、または HHOOKS_RUN_IF() または HHOOKS_RUN_IF_LOOKUP() マクロを通して間接的に呼び出され、スリープ不可能な読み込みロックは、すべての登録されたフック関数への呼び出しにわたって獲得され、保持されます。

戻り値

hhook_head_register() は、エラーが発生しなかったなら、0 を返します。同じ hook_typehook_id でフックポイントが既に登録されているなら、EEXIST を返します。実装が仮想化されていないサブシステム (詳細については 「バグ」 セクションを参照) でフックポイントをまだサポートしていないので、 HHOOK_HEADISINVNET フラグが flags で設定されないなら、EINVAL を返します。 malloc(9) が新しい struct hhook_head のためのメモリの割り付けに失敗したなら、ENOMEM を返します。

hhook_head_deregister() と hhook_head_deregister_lookup() は、エラーが発生しなかったなら、0 を返します。それらは、 hhh が NULL であるなら、ENOENT を返します。それらは、 hhh の参照カウントが 1 より大きいなら、EBUSY を返します。

使用例

よく論評された例の Khelp モジュールを次で見つけることができます。 /usr/share/examples/kld/khelp/h_example.c

tcp(4) の実装は、接続が確立されたフェーズのとき、送信/受信されたパケットのために呼び出される 2 つの hhook ポイントを提供しています。次のファイルで HHOOK を検索します: sys/netinet/tcp_var.h, sys/netinet/tcp_input.c, sys/netinet/tcp_output.csys/netinet/tcp_subr.c

関連項目

khelp(9)

謝辞

このソフトウェアの開発とテストは、Community Foundation Silicon Valley において FreeBSD Foundation と Cisco University Research Program Fund からの助成金によって一部可能となりました。

歴史

hhook フレームワークは、 FreeBSD 9.0 ではじめて登場しました。

hhook フレームワークは、 Advanced Internet Architectures、Melbourne、Australia のために Swinburne University of Technology の Centre において研究している間に、 Lawrence Stewart によって 2010 年に始めてリリースされました。その他の詳細は、次で利用可能です:

http://caia.swin.edu.au/urp/newtcp/

作者

hhook フレームワークは、 Lawrence Stewart <lstewart@FreeBSD.org>によって書かれました。

このマニュアルページは、 David Hayes <david.hayes@ieee.org>と Lawrence Stewart <lstewart@FreeBSD.org>によって書かれました。実装への最小の内部の変更は、これを記述しなければなりません。

June 21, 2013 FreeBSD