EN JA
NETGRAPH(4)
NETGRAPH(4) FreeBSD Kernel Interfaces Manual NETGRAPH(4)

名称

netgraphカーネルネットワークサブシステムを基づくグラフ

解説

netgraph システムは、様々なネットワーク機能を実行するカーネルオブジェクトの実装のための均一でモジュール化されたシステムを提供します。 ノード として知られているオブジェクトは、任意の複雑なグラフとしてアレンジすることができます。ノードは、グラフでエッジ (端) を形成して、 2 つのノードを一緒に接続するために使用される フック を持っています。ノードは、データを処理する、プロトコルを実装するなどのためにエッジ (端) に沿って通信します。

netgraph の目的は、既存のカーネルネットワークインフラストラクチャ (基盤) を置き換えるよりはむしろ補うことです。それは、次を提供します:

  • プロトコルとリンクレベルドライバを組み合わせるフレキシブルな方法。
  • 新しいプロトコルを実装するためのモジュール化した方法。
  • カーネル実体が相互通信するための共通のフレームワーク (枠組み)。
  • 合理的に速くて、カーネルベースの実装。

ノートとタイプ

netgraph で最も基本的な概念は ノード のものです。すべてのノードは、明確な方法で他のノードとそれらと交信する多くの前もって定義されたメソッドを実装します。

各ノードには、ノード作成時間に確定されるノードの静的な特性である タイプ があります。ノードのタイプは、ユニークな ASCII タイプ名によって表現されます。タイプは、ノードが何を行うか、そしてどのように他のノードと接続されるかという意味を含みます。

オブジェクト指向言語では、タイプは、クラスであり、ノードは、それらの個別のクラスのインスタンスです。すべてのノードタイプは、一般的なノードタイプのサブクラスであり、したがって、ある共通の機能と能力 (例えば、 ASCII 名を持つ能力) を継承します。

ノードは、ノードを参照するために使用できるグローバルでユニークな ASCII 名に割り当てられます。名前は、文字‘ .’または‘ :’を含んではいけません、そして、 NG_NODESIZ 文字 (終端の NUL バイトを含んで) に制限されています。

各のノードのインスタンスには、32 ビットの 16 進数値で表現されるユニークな ID 番号 があります。この値は、それに割り当てられた ASCII 名がないとき、ノードを参照するために使用されます。

フック

ノードは、各ノードから 1 つの、1 組の フック を接続することによって他のノードに接続されます。データは、接続された 1 組のフックに沿ってノード間を双方向で流れます。ノードには、必要とするくらい多くのフックがあり、フックに必要とされるどんな意味も割り当てられます。

フックには、これらの特性があります:

  • フックは、そのノード上のすべてのフックの中でユニークな (他のノード上の他のフックには、同じ名前があるかもしれません) ASCII 名があります。名前は、文字‘ .’または‘ :’を含んではいけません、そして NG_HOOKSIZ 文字 (終端の NUL 文字を含んで) に制限されています。
  • フックは、常に別のフックに接続されます。すなわち、フックは、それらが接続されるとき作成され、どちらかのフックが取り除かれ両方のフックが破壊されることによってエッジ (端) は、切断されます。
  • フックは、着信パケットが直接配信されるよりむしろ入力キューシステムによって常にキューに入れられる状態の中に設定することができます。割り込みハンドラからデータを送るとき、これを使用することができ、処理は、他の割り込みをブロックしないように迅速でなければなりません。
  • フックは、最優先の受信データと受信メッセージ関数を供給できます。その受信メッセージ関数は、一般的なノード全体のメソッドに優先してそのフックを通して受信されたデータとメッセージのために使用されるべきです。

ノードは、特別な意味をいくつかのフックに割り当てると決定します。例えば、 debug というフックに接続することは、そのフックにデバッグ情報を送信し始めることによってノードは、トリガされます。

データフロー

2 つのタイプの情報がノード間を流れます: データメッセージとコントロールメッセージです。データメッセージは 1 度に 1 つのエッジをグラフ中のエッジに沿った mbuf チェーン で渡されます。チェーンにおける最初の mbufM_PKTHDR フラグが設定されなければなりません。各ノードは、フックの 1 つを通して受信されたデータを操作する方法を決定します。

また、データと共に、ノードは、コントロールメッセージを受信することができます。汎用とタイプ特有のコントロールメッセージがあります。コントロールメッセージは、共通のヘッダ形式があり、タイプ特有のデータが続き、効率のためにバイナリ構造体です。しかしながら、ノードタイプは、デバッグとヒューマンインタフェース目的 (以下の NGM_ASCII2BINARYNGM_BINARY2ASCII 一般的なコントロールメッセージを参照) のためにバイナリと ASCII フォーマット間の特有のデータのタイプの変換もサポートします。ノードは、これらの変換をサポートする必要はありません。

コントロールメッセージをアドレス指定する 2 つの方法があります。 2 つのノードを接続するエッジのシーケンスがあるなら、メッセージは、メッセージ (相対アドレシング) のための宛先 (終点) アドレスとして ASCII フック名に対応するシーケンスを指定することによって、“ソース (始点) 経路”となります。宛先 (終点) が発信元 (始点) に隣接しているなら、発信元 (始点) ノードは、単に、メッセージが送られるべきであるフックを (コードのポインタとして) 指定します。そうでなければ、受取人のノードのグローバルな ASCII 名 (または同等な ID を基とする名前) は、メッセージ (絶対アドレス指定) の宛先 (終点) アドレスとして使用されます。 2 つのタイプの ASCII アドレス指定は、絶対開始ノードとフックのシーケンスを指定することによって結合されます。 ASCII アドレッシングモードだけが、カーネルの外で制御プログラムに利用可能です。ダイレクトポインタの使用は、カーネルモジュールに制限されます。

メッセージは、しばしば反対の方向の応答メッセージがあとに続くコマンドを表します。これを容易にするために、アドレス指定された応答のために適切な“返送アドレス”をコントロールメッセージの受取人に提供します。

各コントロールメッセージは、メッセージのタイプ、すなわちそれをどのように解釈するか、を示す“typecookie”と呼ばれる 32 ビットの値を含んでいます。通常、各タイプは、解釈するというメッセージのためにユニークな typecookie を定義します。しかしながら、ノードは、2 つ以上のタイプのメッセージを認識して実装するために選択することができます。

メッセージが (その ID またはグローバルな名前を使用することで直接アドレス指定されたのと対照的に) それが特定のフックを通してそのノードに到着したアドレスを含むアドレスに配信されるなら、フックは、その受信ノードに特定されます。メッセージは、再ルートされるか受け継がれることができ、データパケットがノードの間で渡されるのとほぼ同じ方法で、これが必要なノードが決めるべきです。フロー制御とリンク管理目的のための一連の標準のメッセージは通常、このように渡されるベースシステムによって定義されます。通常、フロー制御メッセージはそれらが関係するデータと逆の方向に進行します。

netgraph は (通常) 機能的

待ち時間を最小にするために、ほとんどの netgraph 操作は、機能的です。すなわち、データとコントロールメッセージは、キューとメールボックスを使用することよりむしろ関数呼び出しを行うことによって配信されます。例えば、ノード A がデータ mbuf を隣接しているノード B に送りたいなら、一般的な netgraph データ配信関数を呼び出します。この関数は、順番にノード B と呼び出し B の“受信データ”メソッドを位置付けます。これへの例外があります。

各ノードには、入力キューがあり、それらがノードの状態を変更するので、いくつかの操作は writers (書き込み側) となると考えることができます。明らかに、SMP 世界では、別のデータパケットがノードを通過していた間、ノードの状態を変更されるなら、悪くなるでしょう。このために、入力キューはノード中に書き込み側があるときのように reader/writer (読み込み側/書き込み側) セマンティックを実装し、他のすべての要求は、キューに入れられ、さらに読み込み側、書き込み側、どんな次のパケットもキューに入れられます。データをキューに入れる理由がない場合では、入力メソッドは、上記のように直接呼び出されます。

ノードは、すべての要求が書き込み側とみなされはずであるか、または特定のフックを越えて入る要求が書き込み側であるとみなされるはずであるか、または特定のフックを越えて去るかまたは入るパケットは (すばやくハードウェアに戻りたい割り込みルーチンでしばしば役に立つ) 直接配信するよりむしろ常にキューに入れるべきであると宣言するかもしれません。デフォルトで、すべてのコントロールメッセージパケットはそれらの定義で読み込み側であることを明確に宣言されない場合、書き込み側であるとみなされます。 ( < ng_message.h> 中の NGM_READONLY を参照してください。)

この操作モードが良い性能の結果となりますが、ノード開発者のためにいくつかの意味を持っています:

  • ノードがデータかコントロールメッセージを配信するするときは、いつも、ノードは、オリジナルの配信関数呼び出しが返る前に返っているメッセージを受信する可能性を考慮する必要があります。
  • netgraph は、ノードの間の内部の同期を行います。データは、常に エッジノード で“グラフ”に入ります。 エッジノードnetgraph とシステムのある他の部分の間をインタフェースで接続するノードです。“エッジノード”に関する例は、デバイスドライバ, socket, ether, ttyksocket ノードタイプを含んでいます。これらの エッジノード では、呼び出しスレッドは、ノードで直接コードを実行し、そしてグラフ中でいくつかのエッジの向こう側にデータを配信するために netgraph フレームワークでの要求するコードから実行します。実行の観点から、呼び出しスレッドは netgraph フレームワークメソッドを、そうするためにロックを取得できるなら、次のノードの入力メソッドを実行します。データがいくつかのデバイスかシステムエンティティ (実体) のために破棄されるか、キューに入れられるか、またはスレッドが次のノードでロックを取得することができないかのいずれかまで、これは、続きます。その場合には、データは、ノードのためにキューに入れられ、実行は、オリジナルの呼び出しエンティティ (実体) に rewind back します。訳注: 意味不明。キューに入れられたデータは、それらの操作を完了したとき、ロックの現在の所有者かそれとも、そのようなキューに入れられた item があるとき活性化された特別の netgraph スレッドによって (キューから) 取り出し、処理されます。
  • グラフがサイクルを含んでいるなら、無限ループが起こる可能性があります。

今までのところ、これらの問題は、実際に問題があると判明しませんでした。

カーネルの他の部分との相互作用

ノードには、デバイスハードウェア、カーネルプロトコルスタックなどのように netgraph サブシステムにおけるカーネルの外側の他のコンポーネントとの隠された相互作用があります。事実上、 netgraph の利点の 1 つは、一貫した通信フレームワークでの異種のカーネルネットワークエンティティ (実体) を結合させる能力です。

実例は、プロトコルファミリ PF_NETGRAPHnetgraph ノードと socket(2) の両方である socket ノードタイプです。ソケットノードでユーザプロセスは netgraph に参加できます。他のノードは、普通のメソッドを使用するソケットノードを使用して通信し、ノードは、協力ユーザプロセスとやりとりする情報も渡されたという事実を隠します。

別の例は、ハードウェアへのノードインタフェースを提示するデバイスドライバです。

ノードのメソッド

ノードは、次のノードメソッドへの関数呼び出しによって次の動作について通知され、そして受け付けるか、または (適切なエラーコードを返して) 拒絶されます:
新しいノードの作成
タイプのコンストラクタが呼び出されます。新しいノードの作成が許されるなら、コンストラクタのメソッドはそれが必要とするいくらかの特別のリソースを割り付けます。ハードウェアに対応するノードに関しては、一般的にデバイスのアタッチルーチンの間に行います。しばしば、デバイス名に対応するグローバルな ASCII 名は、同様にここに割り当てられます。
新しいフックの作成
フックは、作成され試験的にノードにリンクされます、そしてノードは、このフックについて説明するのに使用される名前に関して伝えられます。ノードは、それが必要とするいくらかの特別のデータ構造体をセットアップするか、またはフックの名前に基づく接続を拒絶するかもしれません。
2 つのフックの成功した接続
両端がそれらのフックを受け付けて、リンクが作られていた後に、ノードは、それらのピア (相手) がリンクされているのが誰かを見つける機会を得て、次に、接続を拒絶すると決定することができます。分解 (tear-down) は、自動的です。また、これは、ノードが queueing モードに特定のフック (またはそのピア) を設定するかどうか決める時です。
フックの破棄
ノードは、壊れた接続について通知されます。ノードは、いくつかのフックは、クリティカルな操作であり、他は、使い捨てであると考えられます: 1 つのフックの切断は、ノードの全部のシャットダウンに影響するかもしれない別のものの間に受け付けできるイベントであるかもしれません。
ノードのシャットダウン前処理
このメソッドは、以下で議論される本当のシャットダウンする前に呼び出されます。この方法のときに、ノードが完全に操作可能であり、“goodbye”メッセージをピアに送信することができます、または、チェーンからそれ自体を取り除き、 ng_tee(4) ノードタイプのように、ピアを一緒に再接続することができます。
ノードのシャットダウン
このメソッドは、ノードをクリーンアップして、このとき実行す必要があるどんな動作も行われることをを保証します。メソッドは、ノードの一般的なコンポーネントを取り除く一般的な (すなわち、スーパクラス) ノードのデストラクタを呼び出さなければなりません。いくつかのノード (通常 1 部のハードウェアに関連している) はシャットダウンは、すべてのエッジ (端) を切断しノードをリセットしますが、それを取り除かないので、 永続的 です。この場合、シャットダウン方法は、リソースを解放するべきではありませんが、むしろ、クリーンアップして、次にシャットダウンが中断される一般的なコードにシグナルを送るために NG_NODE_REVIVE() マクロを呼び出します。ハードウェアの撤去または ( ng_rmnode_self() によって) アンロードするために、ノード自体によって開始されたシャットダウンの場合、それは、存続しないそれ自体のシャットダウン方法にシグナルを送るために NGF_REALLY_DIE フラグを設定すべきです。

送信と受信データ

また、他の 2 つのメソッドがすべてのノードでサポートされます:
受信データメッセージ
item として通常参照される、 netgraph queueable request item (キューに入れることができる要求 item) は、この関数によって受信されます。 item は mbuf へのポインタを含んでいます。

ノードは、どのフックに item が到着するかが通知され、処理決定でこの情報を使用することができます。受信ノードは、完了時またはエラー時に、常に mbuf チェーンNG_FREE_M() (解放) しなければならないか、または他のノード (またはカーネルモジュール) にそれを渡します。そこでは、それを解放する責任があります。同様に、 item は、それを他のノードに渡さないなら、 NG_FREE_ITEM() マクロを使用して解放しなければなりません。 item が解放時点で mbuf の参照をまだ保持しているなら、また、それらは、適切に解放されます。したがって、 mbuf が変更されるか item から別々に解放される可能性があるなら、 item の中で参照を取り除く NGI_GET_M() マクロを使用して検索することもたいへん重要です。 (または、同じオブジェクトを複数解放することが生じます。)

mbuf の内容のみを調べる必要があるなら、 item の中で mbuf ポインタを読み込み、再書き込みする NGI_M() マクロを使用することができます。

開発者が、 mbuf チェーン に伴うどんなメタ情報も渡す必要があるなら、彼は mbuf_tags(9) フレームワーク (枠組み) を使用するべきです。

古い netgraph の特定のメタデータ形式が現在時代遅れであることに注意してください。

受信ノードは netgraph NETISR システム (下記参照) で、キューに入れることによってデータを延期すると決定するかもしれません。データが到着するフックの flags ワードで HK_QUEUE フラグの設定によって達成します。インフラストラクチャは、直接それを配信するよりむしろビットとその後になって配信されるデータをキューに入れることを順守します。ノードは、それ自体の出力パケットがキューに入れられるように、 ピア ノードでビットを設定することに決定します。

ノードは、コード化を簡素化するために特定のフック上で受信されたデータのために異なった受信データ関数を指名するために選びます。それは、これをするために NG_HOOK_SET_RCVDATA( hook, fn) マクロを使用します。関数は、そのフックからのすべての (単に) パケットを受信する以外のあらゆる方法で同じ引数を受信します。

受信コントロールメッセージ
このメソッドは、コントロールメッセージがノードにアドレス指定されるとき、呼び出されます。受信されたデータのように、 item は、コントロールメッセージへのポインタで受信されます。メッセージは、 NGI_MSG() マクロを使用して調べることができるか、または item の中で参照を取り除く NGI_GET_MSG() を使用して item から完全に抽出するすることができます。 item が解放される ( NG_FREE_ITEM() を使用して) とき、まだメッセージの参照を保持しているなら、メッセージは、適切に解放されます。参照を取り除いてあるなら、ノードは、 NG_FREE_MSG() マクロを使用してメッセージ自体を解放しなければなりません。返送アドレスは、後でいつでも返答メッセージを送ることができるように由来するメッセージのノードのアドレスを与えて、常に供給されます。返りアドレスは、 NGI_RETADDR() マクロを使用して item から検索されます、そしてそのタイプは ng_ID_t です。すべてのコントロールメッセージと応答は、タイプ M_NETGRAPH_MSGmalloc(9) で割り付けられます。しかしながら、メッセージを割り当てて、書き込むために NG_MKMESSAGE() と NG_MKRESPONSE() マクロを使用すればより便利です。メッセージは NG_FREE_MSG() マクロを使用して解放されなければなりません。

メッセージが特定のフックを通して配信されるなら、そのフックは、それが到着したときノードが別のフックでメッセージをそれに転送したがっているところで、フロー制御メッセージ、および状態変更メッセージのようなものの使用を許すことが明らかになります。

ノードは、コード化を簡素化するために特定のフック上で受信されたメッセージのために異なった受信メッセージ関数を指名するために選択できます。それは、これを行うために NG_HOOK_SET_RCVMSG( hook, fn) マクロを使用します。関数は、フックからのすべての (唯一の) メッセージを受信する以外のあらゆる方法で同じ引数を受信します。

すべての参照の解放されたノードが自動的に解放できるように、参照カウントでいろいろ使われ、この振る舞いは“タイプモジュール”書き込みが使用する一貫して信頼できるフレームワークを提示するためにテストされてデバッグされています。

アドレス指定

netgraph フレームワークは、明白であり、グラフで任意の 1 つのノードのアドレス指定を記述する方法を簡単に利用できるように提供されます。ノードの名前付けは、タイプから独立しており、別のノード、または外部のコンポーネントは、一般的なメッセージタイプを送信するためにそれのアドレス指定するノードのタイプに関して何も知る必要はありません。ノードとフック名は、アドレス指定を意味あるものとするように選ばれるべきです。

アドレス指定は、絶対的または相対的です。絶対的アドレス指定は、ノード名または ID で始まって、コロンがあとに続いて、ピリオドで分離されたフック名のシーケンスが続きます。これは、指定されたノードで始まって、フックの指定されたシーケンスが続くことによって到達したノードをアドレス指定します。相対的アドレスは、ローカルノードで暗黙のうちにフックの横断を始めるフック名のシーケンスだけを含んでいます。

ノード名のための 2、3 の特別な可能性があります。名前‘ .’ (‘ .:’として参照される) は、常にローカルノードを参照します。また、グローバルな名前を持っていないノードは、角括弧の中に ID 番号の 16 進数表現を囲むことによって、それらの ID 番号でアドレス指定ができます。ここに、有効な netgraph アドレス指定のいくつかの例があります:

.: 
[3f]: 
foo: 
.:hook1 
foo:hook1.hook2 
[d80]:hook1

次の一連のノードは DLCI 16 と DLCI 20 上の PPP フレームで RFC-1490 フレームを備える 2 つのアクティブな論理 DLCI チャネルを持っている 1 つの物理的なフレームリレーラインでサイトのために作成されるかもしれません:

[type SYNC ]                  [type FRAME]                 [type RFC1490] 
[ "Frame1" ](uplink)<-->(data)[<un-named>](dlci16)<-->(mux)[<un-named>  ] 
[    A     ]                  [    B     ](dlci20)<---+    [     C      ] 
                                                      | 
                                                      |      [ type PPP ] 
                                                      +>(mux)[<un-named>] 
                                                             [    D     ]

名前“ Frame1:uplink.dlci16”を使用することによって、コントロールメッセージをどこからでもノード C に常に送信することもあり得ます。またこの場合、ノード C は、フック mux を通してそれに到達したメッセージが通知されます。同様に、“ Frame1:uplink.dlci20”は、ノード D に確実に到達するために使用されるかもしれませんし、そして、ノード A は、ノード B を“ .:uplink”または単に“ uplink”として参照するかもしれません。逆に、B は“ data”として A を参照できます。アドレス“ mux.data”は、ノード A にメッセージをアドレス指定するために、ノード C と D の両方によって使用されるかもしれません。

これは コントロールメッセージ のためだけであることに注意してください。それぞれのこれらの場合では、相対的なアドレッシングモードが使用されるところで、発信元のノードと同様に、受信側は、メッセージが到着したフックについて通知されます。これは、メッセージの中継点ごと (hop-by-hop) の配信のオプションと状態情報を許します。データメッセージは、各ノードが次の経路制御 (ルーティング) を決定し、出発フックを指定することによって、一度に 1 つの中継点 (hop) だけに 経路制御されます。したがって、B がフック data でフレームを受信するとき、DLCI を決定するためにフレームリレーヘッダをデコードして、次にアンラップ (包みを解かれた) されたフレームを C か D のどちらかに転送します。

同様の方法で、フロー制御メッセージは、発信データへの反対の方向に経路制御 (route) されます。例えば、“ Frame1:”からの“buffer nearly full” (ほとんどバッファは、満杯) というメッセージは同様のメッセージをノード C と D の両方に送信すると決定するノード B に渡されます。ノードは、メッセージを経路制御するために direct hook pointer (ダイレクトフックポインタ) アドレス指定を使用します。メッセージは“ Frame1:”から同期応答、時間とサイクルの節約として B に移動するかもしれません。

netgraph 構造体

構造体は (ノードにとって重要なカーネル構造のための) < netgraph/netgraph.h> と (また、ユーザプログラムとって重要なメッセージ定義のための) < netgraph/ng_message.h> で定義されます。

ノードの作者にとって重要な 2 つの基本的なオブジェクトタイプは ノードフック です。これらの 2 つのオブジェクトには、ノードの書き込み側にとって重要な次の特性があります。

struct ng_node
ノードの作者は、それらのポインタを宣言するために、常に次の typedef を使用するべきであり、実際に構造体を決して宣言するべきではありません。

typedef struct ng_node *node_p;

以下の特性は、ノードに関連していて、次の方法でアクセスすることができます:

妥当性
ドライバまたは割り込みルーチンは、ノードがまだ有効であるかどうかチェックしたがっているかもしれません。呼び出し側がノードに関する参照を保持するのでそれは、解放されていないと仮定されます。しかしながら、それは、無効にされたか、またはそうでなければシャットダウンされているかもしれません。 NG_NODE_IS_VALID( node) マクロを使用すると、この状態は、戻ります。結局、無効のノードで実行するコードがほとんど不可能のはずですが、このとき、その仕事は、終了していません。
ノード ID ( ng_ID_t)
NG_NODE_ID( node) を使用することでこの特性を検索することができます。
ノード名
オプションのグローバルでユニークな名前で ヌル文字 で終る文字列です。ここに値があれば、それは、ノードの名前です。

if (NG_NODE_NAME(node)[0] != '\0') ... 
 
if (strcmp(NG_NODE_NAME(node), "fred") == 0) ...
ノードに依存する不透明なクッキー
どうようなポインタタイプでもここに置くことができます。マクロ NG_NODE_SET_PRIVATE( node, value) と NG_NODE_PRIVATE( node) は、それぞれ、この特性を設定して、検索します。
フックの数
NG_NODE_NUMHOOKS( node) マクロは、この値を検索するために使用されます。
フック
ノードには、多くのフックがあります。すべてのフックが何らかの状態であるかどうかテストすることができるように縦断方法を提供します。 NG_NODE_FOREACH_HOOK( node, fn, arg, rethook) ここで fnfn( hook, arg) の形式で、各フックで呼び出される関数で、 0 を返すことで検索を終了します。検索が終了するなら、 rethook は、検索が終えられたフックに設定されます。
struct ng_hook
ノードの作者は、それらのポインタを宣言するために、常に次の typedef を使用するべきです。

typedef struct ng_hook *hook_p;

以下の特性は、ノードに関連していて、次の方法でアクセスすることができます:

フックに依存する不透明なクッキー
どうようなポインタタイプでもここに置くことができます。マクロ NG_HOOK_SET_PRIVATE( hook, value) と NG_HOOK_PRIVATE( hook) は、それぞれ、この特性を設定して、検索します。
関連ノード
マクロ NG_HOOK_NODE( hook) は、関連ノードを見つけます。
ピアフック ( hook_p)
この接続された相手の他のフック。 NG_HOOK_PEER( hook) マクロは、ピア (相手側) を見つけます。
参照
NG_HOOK_REF( hook) と NG_HOOK_UNREF( hook) マクロは、フック参照カウントをそれに応じて、増加して、減少させます。減少の後に、利用者は、別の参照がまだ有効でないいならフックが解放されたと常に仮定するべきです。
オーバライド受信関数
NG_HOOK_SET_RCVDATA( hook, fn) と NG_HOOK_SET_RCVMSG( hook, fn) マクロは、一般的な受信データと受信メッセージ関数に優先して使用されるオーバライド方法を設定するために使用することができます。これらの設定を取り消すには、それらを NULL に設定するマクロを使用します。それらは、それらが設定されるフック上で受信されたデータとメッセージに使用されるだけです。

各ノードのためのフックの名前、参照カウント、およびリンクリストの維持管理は netgraph サブシステムで自動的に処理されます。通常、ノードのプライベート情報は、ノードかフック構造体への逆方向のポインタを含んでいます。フック構造体は、ノードのための参照カウントに含まなければならない新しい参照としてカウントします。ノードコンストラクタが呼び出されるとき、ノードが破壊されるとき、ノードで忘れずに NG_NODE_UNREF() をするべきであるように、既に計算された参照があります。

フックから、利用者は、対応するノード、およびすべてのアクティブなフックを横断することが可能なノードから取得することができます。

どのようにノードを定義するかの現在の例は、 src/sys/netgraph/ng_sample.c でいつも見ることができ、新しいノードの書き込み側の出発点として使用されるべきです。

netgraph メッセージ構造体

コントロールメッセージには、次の構造体があります:

#define NG_CMDSTRSIZ    32      /* 最大コマンド文字列 (ヌル文字を含む) */ 
 
struct ng_mesg { 
  struct ng_msghdr { 
    u_char      version;        /* NG_VERSION と等しくなければ 
                                   ならない */ 
    u_char      spare;          /* 2 バイトの詰めもの */ 
    u_short     arglen;         /* コマンド/応答データの長さ */ 
    u_long      flags;          /* メッセージ状態フラグ */ 
    u_long      token;          /* 応答は, 同じトークンがあるべき */ 
    u_long      typecookie;     /* このメッセージを理解するノードタイプ */ 
    u_long      cmd;            /* コマンド識別子 */ 
    u_char      cmdstr[NG_CMDSTRSIZ]; /* コマンド文字列 (デバッグ用) */ 
  } header; 
  char  data[0];                /* コマンド/応答データの開始 */ 
}; 
 
#define NG_ABI_VERSION  5               /* netgraph カーネル ABI 
                                           バージョン */ 
#define NG_VERSION      4               /* netgraph メッセージバージョン */ 
#define NGF_ORIG        0x0000          /* コマンド */ 
#define NGF_RESP        0x0001          /* 応答 */

コントロールメッセージは、上で示される固定ヘッダがあり、タイプクッキーとコマンドによって決まる可変長のデータセクションが続きます。各フィールドは、次に説明されます:

version
netgraph メッセージプロトコル自体のバージョンを示します。現在のバージョンは NG_VERSION です。
arglen
これは data で始まる、任意の特別の引数の長さです。
flags
これがコマンドまたは応答コントロールメッセージであるかどうかを示します。
token
token は、送信側が応答メッセージを対応するコマンドメッセージに一致させることができる手段です。応答は、常に同じトークン (token) があります。
typecookie
対応するノードタイプのユニークな 32 ビットの値です。ノードがタイプクッキーを認識しないなら、 EINVAL を返すことによってメッセージを拒否しなければなりません。

各タイプには、それ自体のメッセージのためにコマンド、引数形式、およびクッキーを定義するインクルードファイルがあるべきです。 typecookie は、同じヘッダファイルが送信側と受信側の両方によって含まれていたことを保証します。ヘッダファイルの非互換な変更を行うとき、 typecookie は、変更 されなければなりません。 ユニークなタイプクッキーを生成するための事実上のメソッドはヘッダファイルが書き込まれているときの (すなわち、“ date -u +%s”の出力) エポックからの秒数となります。

一般的な ノードタイプのために前もって定義された typecookie NGM_GENERIC_COOKIE、およびすべてのノードが理解している対応する一組の一般的なメッセージがあります。これらのメッセージの処理は、自動的です。

cmd
メッセージコマンドのための識別子です。これは、タイプ特有であり、 typecookie と同じヘッダファイルで定義されます。
cmdstr
コマンド (デバッグ目的だけのための) の短い人間が読めるバージョンの場所です。

いくつかのモジュールは、2 つ以上のヘッダファイルからのメッセージを実装するために選択することができ、したがって、2 つ以上のタイプクッキーが認識されます。

コントロールメッセージ ASCII 形式

コントロールメッセージは、効率のためのバイナリ形式になっています。しかしながら、デバッグとヒューマンインタフェースの目的のために、ノードタイプがサポートしているなら、コントロールメッセージは、同等な ASCII 形式と相互に変換されるかもしれません。 ASCII 形式は、次の 2 つの例外でバイナリ形式と同様です:
  1. cmdstr ヘッダフィールドは cmd ヘッダフィールドに対応している、コマンドの ASCII 名を含まなければなりません。
  2. 引数フィールドは、メッセージ引数の ヌル文字 で終わる ASCII 文字列バージョンを含んでいます。

一般的に、コントロールメッセージの引数フィールドはどんな任意の C データタイプとなることができます。 netgraph は、つぎの簡単な構文を備える ASCII でいくつかの前もって定義されたデータタイプをサポートするために解析ルーチンを含んでいます:

  • 整数タイプは 8、10、または 16 の基本数で表されます。
  • 文字列は、二重引用符で囲まれ、普通の C 言語バックスラッシュエスケープに順守します。
  • IP アドレスは、明白な形式があります。
  • 配列は、インデックス 0 で始まる連続してリストされた要素の角括弧で囲まれます。要素には、それに先行するオプションのインデックスと等号 (‘ =’) があるかもしれません。要素に明白なインデックスがないときはいつでも、インデックスは、暗黙に要素の前のインデックスに 1 を加えます。
  • 構造体は、中括弧で囲まれ、各フィールドは、形式 fieldname= value で指定されます。
  • 値が“デフォルト値”と等しい任意の配列の要素か構造体のフィールドは、省略されるかもしれません。整数型では、通常、デフォルト値は 0 です。文字列型では、空の文字列です。
  • 配列の要素と構造体のフィールドは、任意の順序で指定されるかもしれません。

各ノードタイプは、解析するためと非解析するために必要なルーチンを提供することによって、それ自体の任意のタイプを定義できます。特定のノードタイプのために定義された ASCII 形式は、対応するマニュアルページに文書化されています。

一般的なコントロールメッセージ

直接フレームワーク自体でサポートされる、すべてのノードのために動作している多数の標準の前もって定義されたメッセージがあります。これらは、メッセージの基本的なレイアウトと他の同様の情報とともに < netgraph/ng_message.h> で定義されます。
NGM_CONNECT
両端で供給されたフック名を使用して、別のノードに接続します。
NGM_MKPEER
与えられたタイプのノードを接続し、次に、供給されたフック名を使用してそれに接続します。
NGM_SHUTDOWN
ターゲットノードは、すべての隣接ノードを切断しシャットダウンするべきです。物理的なハードウェアを表すようなパーシステント (持続的) ノードはノード名前空間から消え去るわけではありませんが、単にそれら自体をリセットします。ノードは、すべてのフックを切断しなければなりません。これは、隣接ノード自体のシャットダウンとことによると全体の接続グラフのカスケード (段階的な) のシャットダウンをもたらすかもしれません。
NGM_NAME
名前をノードに割り当てます。名前を持たないノードは、存在でき、これは NGM_MKPEER メソッドを使用することで作成されるノードのデフォルトです。そのようなノードは、相対的かまたはそれらの ID 番号でのみアドレス指定することができます。
NGM_RMHOOK
ノードは、隣接ノードの一つにフック接続を切るように依頼します。両方のノードは、それらの“disconnect” (切断) メソッドを呼び出します。どちらのノードも、結果として完全にシャットダウンすることを選ぶかもしれません。
NGM_NODEINFO
ターゲットノードにそれ自体を説明するように依頼します。 4 つの返されたフィールドは (指定されるなら) ノード名、ノードタイプ、ノード ID とアタッチされたフックの数です。 ID は、そのノードにユニークな内部の数です。
NGM_LISTHOOKS
これは、 NGM_NODEINFO によって与えられた情報を返しますが、さらに、各リンクについて説明するフィールドの配列とそのリンクの遠端でノードのための説明を含んでいます。
NGM_LISTNAMES
これは、指定されたノードについて説明する配列の各エントリである、 ( NGM_NODEINFO のような) ノード記述の配列を返します。すべての指定されたノードが説明されます。
NGM_LISTNODES
これは、それらに名前があるかどうかにかかわらず、すべてのノードがリストされていることを除いて、 NGM_LISTNAMES と同じです。
NGM_LISTTYPES
これは、現在インストールされているすべての netgraph タイプのリストを返します。
NGM_TEXT_STATUS
ノードは、テキストでフォーマットされた状態メッセージを返します。状態情報は、完全にノードタイプによって決定されます。それは、ノードそれ自体の中のサポートを必要とし、このメッセージをサポートしないように選ぶノードのような唯一の“一般的な”メッセージです。テキスト応答は NG_TEXTRESPONSE (現在 1024) バイトより少なくなければなりません。これは、人間が読める形式で一般的な状態情報を返すために使用できます。
NGM_BINARY2ASCII
このメッセージは、バイナリのコントロールメッセージを ASCII 形式に変換します。変換される全体のコントロールメッセージは NGM_BINARY2ASCII メッセージ自体の引数フィールドの中に含まれています。成功すれば、応答は ASCII 形式の同じコントロールメッセージを含みます。ノードは、一般的にそれ自体を理解するメッセージを変換する方法を知っているだけであるので、 NGM_BINARY2ASCII のターゲットノードは、しばしば実際にそのメッセージを受信する同じノードです。
NGM_ASCII2BINARY
NGM_BINARY2ASCII. の反対です。 ASCII 形式で変換される全体のコントロールメッセージは、 NGM_ASCII2BINARY の引数部分に含まれていて、書き込まれている flags, cmdstrarglen ヘッダフィールド、および引数フィールド中の引数の ヌル文字 で終わる文字列のバージョンのみを必要とします。成功すれば、応答は、コントロールメッセージのバイナリのバージョンを含んでいます。

フロー制御メッセージ

グラフに関してノードに影響するコントロールメッセージに加えて、メッセージが定義した多くの フロー制御 もあります。現在のところこれらがシステムによって自動的に取り扱われ ない ので、それらがフロー制御を利用することでグラフで使用されて、これらのメッセージのあり得るパスにあるなら、ノードは、それらを取り扱う必要があります。これらのメッセージを理解していないノードのデフォルト動作はそれらを次のノードに渡さなければなりません。うまくいけばいくつかのヘルパー関数が結局、これを援助します。これらのメッセージは、また、 < netgraph/ng_message.h> で定義されて、それらを特定するのを助けるためにクッキー NG_FLOW_COOKIE を切り離します。それらは、ここで徹底的にカバーされません。

初期設定

基本の netgraph コードは、静的にカーネルにコンパイルされるか、または kldload(8) によって KLD として動的にロードされます。前の場合には、カーネル設定ファイルに

options NETGRAPH

を含めます。また、利用者は、カーネル編集で選択されたノードタイプを含むことができます、例えば:

options NETGRAPH
options NETGRAPH_SOCKET
options NETGRAPH_ECHO

netgraph サブシステムがいったんロードされると、個別のノードタイプは kldload(8) によって KLD モジュールとしていつでもロードできます。そのうえ、 netgraph は、自動的にこれを行う方法を知っています。未知のタイプ type の新しいノードを作成するという要求が行われたとき、 netgraph は、KLD モジュール ng_< type> .ko をロードすることを試みます。

また、特定のデバイスドライバが netgraph ノードとしてデバイスの各インスタンスをエクスポートしたがっているとき、タイプは、ブート時にインストールすることができます。

一般的に、新しいタイプは、ポインタをタイプ struct ng_type 構造体に供給する、 ng_newtype() を呼び出すことによって、いつでもカーネルからインストールすることができます。

NETGRAPH_INIT() マクロは、リンカセットを使用することによって、このプロセスを自動的に行います。

既存のノードタイプ

現在いくつかのノードタイプが存在します。それぞれは、それ自体のマニュアルページに完全に文書化されています:
SOCKET
ソケットタイプは、新しいプロトコルドメイン PF_NETGRAPH で 2 つの新しいソケットを実装しています。新しいソケットプロトコルは、 NG_DATANG_CONTROL で両方ともタイプ SOCK_DGRAM です。それぞれの 1 つは、一般的にソケットノードに関連しています。両方のソケットがクローズしたとき、ノードは、シャットダウンします。 NG_DATA ソケットは、送受信データに使用されます、一方 NG_CONTROL ソケットは、送受信コントロールメッセージに使用されます。データとコントロールメッセージは struct sockaddr_ng ソケットアドレスを使用して、 sendto(2)recvfrom(2) システムコールを使用して渡されます。
HOLE
一般的なメッセージのみに応答し、データのためには“ブラックホール”です。テストに役に立ちます。常に新しいフックを受け付けます。
ECHO
一般的なメッセージのみに応答し、到着したフックを通して常にデータをエコーバックします。それら自身の応答としてどんな一般的でないメッセージを返します。テストに役に立ちます。常に新しいフックを受け付けます。
TEE
このノードは“覗き見 (snooping)”に役に立ちます。それには 4 つのフックがあります: left, right, left2rightright2left です。 right から入るデータは left に渡され、 right2left でコピーされ、 left から入るデータは、 right に渡され、 left2right でコピーされます。 left2right から入るデータは right に送られ、 right2left からのデータは left に送られます。
RFC1490 MUX
カプセル化/非カプセル化されたフレームは RFC 1490 にしたがってコード化されます。カプセル化されたパケット ( downstream (下流)) のためのフックと各プロトコル (すなわち、IP、PPP など) に 1 つのフックがあります。
FRAME RELAY MUX
フレームリレー (Frame Relay) フレームをカプセル化/非カプセル化します。カプセル化されたパケット ( downstream (下流)) のためのフックと各 DLCI に 1 つのフックがあります。
FRAME RELAY LMI
フレームリレー“LMI” (リンク管理インタフェース (link management interface)) 操作とパケットを自動的に取り扱います。いくつかの LMI 規格のいずれかは交換のときに使用中であるかを自動的にプローブして検出します。
TTY
また、このノードは、回線制御規則 (line discipline) です。それは mbuf フレームと TTY が netgraph ノードとして現れるのを許容する、連続したシリアルデータの間で単に変換されます。それには、プログラム可能な“ホットキー (hotkey)”文字があります。
ASYNC
このノードは、RFC 1662 にしたがって非同期フレームをカプセル化と非カプセル化します。これは、非同期シリアルラインで PPP リンクをサポートするために TTY ノードタイプと連結して使用されます。
ETHERNET
このノードは、システム中のあらゆるイーサネットインタフェースにアタッチされます。それは、インタフェースからフレームを送信することと同様にネットワークから生のイーサネットフレームをキャプチャ (捕獲) することを許します。
INTERFACE
また、このノードは、システムネットワークインタフェースです。それには、それぞれのプロトコルファミリ (IP、AppleTalk、IPX など) を意味するフックがあり、 ifconfig(8) の出力で現れます。インタフェースは“ ng0”, “ ng1”などの名前が付けられます。
ONE2MANY
このノードは、簡単なラウンドロビンマルチプレクサ (多重化) を実装します。例えば、2 台のマシンの間の高速度リンクを取得するためにいくつかの LAN ポートを一緒に作動させるために使用することができます。
種々の PPP 関連ノード
netgraph で実行する完全なマルチリンク PPP 実装があります。 net/mpd5 ポートは、大変低いレイテンシ (待ち時間) の高能力 PPP システムを作るためにこれらのモジュールを使用することができます。また、それは、PPTP ノードを使用することで PPTP VPN をサポートします。
PPPOE
サーバとクライアントは PPPoE の実装をサポートします。 ppp(8)net/mpd ポートのどちらかに連動して使用します。
BRIDGE
このノードは、イーサネットノードと共に、たいへんフレキシブルなブリッジシステムを導入できるようにします。
KSOCKET
この興味あるノードは、システムへのソケットに似ていますが、さらなる処理のために netgraph システムからすべてのデータを流用します。これは、UDP トンネルをコマンド行からほぼ自明の実装を行うことをできるようにします。

より多くのノードタイプについては、このマニュアルページの終りのセクションを参照してください。

コントロールメッセージをそれ (例えば、 NGM_NODEINFO) に送信しようとすることによって、指定されたノードが存在するかどうかチェックすることができます。存在していないなら、 ENOENT が返されます。

すべてのデータメッセージは M_PKTHDR フラグセットがある mbuf チェーン です。

ノードは、それらが割り付けるものを解放することに責任があります。 3 つの例外があります:

  1. データリンクの向こう側に送信された mbuf は、送信側によって決して解放されません。エラーの場合は、それらは、解放されているはずと考えられます。
  2. NG_SEND_MSG_*() ファミリマクロの 1 つを使用して送られたメッセージは受信側によって解放されます。上記の場合のように、メッセージに関連しているアドレスはその情報を保存したいなら、受信側は、それらをコピーするべきであるので、それらを割り付けられたかどうかによって解放されます。
  3. コントロールメッセージとデータの両方は netgraph item で配信されキューに入れられます。 item は NG_FREE_ITEM( item) を使用することで解放されるか、または別のノードに渡さなければなりません。

関連ファイル

< netgraph/netgraph.h>
netgraph ノードによってカーネル中でもっぱら使用するための定義。
< netgraph/ng_message.h>
netgraph メッセージを処理する必要があるどんなファイルでも必要とされる定義。
< netgraph/ng_socket.h>
netgraph socket タイプノードを使用する必要がある定義。
< netgraph/ng_>< type> .h
タイプクッキー定義を含んでいる、 netgraph type ノードを使用する必要がある定義。
/boot/kernel/netgraph.ko
netgraph サブシステムロード可能 KLD モジュール。
/boot/kernel/ng_< type> .ko
ノードタイプ type のためのロード可能な KLD モジュール。
src/sys/netgraph/ng_sample.c
骨組み (スケルトン) の netgraph ノード。新しいノードタイプのための出発点としてこれを使用してください。

ユーザモードサポート

netgraph システムと情報をやりとりするユーザモードプログラムをサポートするためのライブラリがあります。詳細については netgraph(3) を参照してください。

2 つのユーザモードサポートプログラム ngctl(8)nghook(8) は、マニュアル設定とデバッグを支援するために利用可能です。

新しいノードタイプをデバッグするためのいくつかの役に立つ技術があります。まず、最初にユーザモードで新しいノードタイプを実装することはデバッグをより簡単にします。 tee ノードタイプも特に ngctl(8)nghook(8) に関連するデバッグの役に立ちます。

また、 netgraph を使用することで解決されたいくつかの一般的なネットワーク問題のための解決策については /usr/share/examples/netgraph の中を見てください。

歴史

netgraph システムは、Whistle InterJet のためにカスタマイズされた FreeBSD 2.2 バージョンを使用して Whistle Communications, Inc. で設計され、最初に実装されました。それは、最初に FreeBSD 3.4 のメインツリー (訳注: CVS 管理されたツリー) でデビューしました。

作者

Archie Cobbs <archie@FreeBSD.org>によって寄贈され Julian Elischer <julian@FreeBSD.org>によって書かれました。
May 25, 2008 FreeBSD