この章では、データサービス用にパブリックモジュールを作成するときに留意すべきアーキテクチャ上の詳細について説明します。
この章は、次の節から構成されています。
サービスプロバイダ層の API 関数は 3 つのカテゴリに分類されます。
データ格納関数 - パブリックモジュールとその基盤となるデータサービス自体に関連する処理を行います。これらの関数には、configure()、mklocation()、status()、version() などが含まれます。
dhcptab コンテナ関数 - dhcptab コンテナを作成したり、dhcptab コンテナに対してレコードを記載したり、dhcptab コンテナ内のレコードのクエリー検索を行なったりします。open_dt() 関数はコンテナのハンドルを作成し、その他の関数はそのハンドルへのポインタをとります。close_dt() 関数は、そのコンテナをクローズするときにハンドルを破棄します。
ネットワークコンテナ関数 - DHCP ネットワークコンテナを作成したり、ネットワークコンテナにレコードを追加したり、ネットワークコンテナ内のレコードをクエリー検索したりします。open_dn() 関数ではコンテナのハンドルを作成し、他の関数ではそのハンドルへのポインタを使用します。close_dn() 関数では、コンテナをクローズするときにハンドルを破棄します。
これらの関数の詳細は、第 3 章「サービスプロバイダ層の API」を参照してください。
DHCP サーバーはマルチスレッド機能を実装しており、多数のクライアントを同時にサポートすることが可能です。DHCP サーバーによるマルチスレッド処理をサポートするためには、パブリックモジュールが MT-安全でなければなりません。
モジュールが MT-安全であるためには、add_d?()、delete_d?()、modify_d?() への呼び出しを同期させ、それらがシリアルに呼び出されるようにする必要があります。たとえば、あるスレッドが、ある DHCP ネットワークコンテナについて add_dn() 内に存在する場合は、他のスレッドが、その同じコンテナについて add_dn()、delete_dn()、modify_dn()、lookup_dn() 内に存在しません。パブリックモジュールがローカルファイルシステムベースのデータサービスをサポートする場合は、これに対処させるために同期サービスを使用することができます。詳細は、ファイルシステムベースのコンテナへのアクセスの同期化を参照してください。
ローカルのファイルシステムベースのデータサービス (データサービスが DHCP サーバーと同じマシンで動作する場合) 内のコンテナにアクセスするパブリックモジュールを作成する場合には、複数のプロセスやスレッドの間で基盤となるデータサービスへのアクセスを同期化するのは難しいことがあります。
Solaris DHCP 同期サービスでは、同期化をフレームワーク構成層へプッシュアップすることにより、ローカルのファイルシステムベースのデータサービスを使用するパブリックモジュールの設計をシンプルにします。このフレームワークを使用するようにモジュールを設計すれば、コードがシンプルになり、設計がよりクリアになります。
この同期サービスは、パブリックモジュールに、add_d?()、delete_d?()、modify_d?() サービスプロバイダ層 API 呼び出しのすべての呼び出し元のコンテナ単位の排他的同期を提供します。つまり、あるスレッドが、ある DHCP ネットワークコンテナについて add_dn() 内に存在する場合は、他のスレッドが、その同じコンテナについて add_dn()、delete_dn()、modify_dn()、lookup_dn() 内に存在しません。ただし、close_dn() のように同期が保証されないルーチン内には、他のスレッドが存在することがあります。
lookup_d?() のすべての呼び出し元は、コンテナ単位で共有的に同期化されます。したがって、多数のスレッドが同じコンテナについて検索を行なっていても、追加、削除、変更の操作は、同時に 1 つのスレッドしか実行できません。
同期サービスは、デーモン (/usr/lib/inet/dsvclockd) として実装されます。パブリックモジュールに代わってなされるロックマネージャの要求は、フレームワーク構成層 API 呼び出しを通して行われます。フレームワーク構成層とロックマネージャデーモン間のインタフェースには、Solaris の door プロセス間通信のメカニズムが使用されます。これについては、例として door_create(3DOOR) や door_call(3DOOR) などを参照してください。
パブリックモジュールが同期化を要求すると、フレームワーク構成層は、dsvclockd デーモンがまだ動作していなければ、これを起動します。デーモンがロックを扱わない時間が 15 分を過ぎると、デーモンは自動的に終了します。この時間を変更する場合は、/etc/default/dsvclockd ファイルを作成し、IDLE のデフォルトをデーモンが終了するまでにアイドルである分数に設定します。
同期サービスが必要なことをパブリックモジュールからフレームワーク構成層に知らせるには、モジュールのソースファイルの 1 つに次のグローバル変数を含めます。
dsvc_synchtype_t dsvc_synchtype = DSVC_SYNCH_DSVCD;
同期サービスが「必要ない」ことをパブリックモジュールからフレームワーク構成層に知らせるには、モジュールのソースファイルの 1 つに次のグローバル変数を含めます。
dsvc_synchtype_t dsvc_synchtype = DSVC_SYNCH_NONE;
現在のところ、同期タイプは DSVC_SYNCH_DSVCD と DSVC_SYNCH_NONE の 2 つだけです。
アーキテクチャは、ファイルベースのモジュールがレコード更新における衝突を回避するのを助ける機能を提供します。サービスプロバイダ API では、レコード単位の更新シグニチャ (符号なしの 64 ビット整数) を使用することによって、データの整合性を維持します。この更新シグニチャは、/usr/include/dhcp_svc_public.h で定義された、d?_rec_t コンテナレコードデータ構造の d?_sig 要素です。アプリケーション/サービス層からフレームワーク構成層 API、およびサービスプロバイダ層 API に至るまで、このアーキテクチャのすべての層が d?_rec_t を使用します。サービスプロバイダ層より上では、更新シグニチャは、フレームワーク構成層 API のユーザーからは操作されない不透明なオブジェクトです。
モジュールは、サービスプロバイダ層 API 関数呼び出しを通して d?_rec_t レコードを受け取ったら、d?_rec_t のキーフィールドとマッチするレコードをデータサービス内で検索し、内部レコードのシグニチャと呼び出しから渡された d?_rec_t を比較する必要があります。内部レコードのシグニチャが、渡されたレコードのものとマッチしない場合、レコードは、その使用者がパブリックモジュールから取得した後で変更されていることを意味します。この場合には、モジュールは、レコードが前に取得されたときから変更されていることを呼び出し元に知らせる DSVC_COLLISION を返す必要があります。シグニチャがマッチする場合は、モジュールは、そのレコードを格納する前に引数レコードの更新シグニチャを増分する必要があります。
モジュールがサービスプロバイダ層 API を通して新しい d?_rec_t レコードを受け取ったら、そのモジュールはそれをコンテナに追加する前に、更新シグニチャに値を設定する必要があります。最もシンプルな方法は、値に 1 を設定する方法です。
ただし、まれなケースとはいえ、シグニチャが常に同じ初期値を持つと、更新における衝突を検出できないことがあります。たとえば、次のような場合です。まず、スレッド A がシグニチャ 1 のレコードを追加し、スレッド B がそのレコードを検索します。次に、スレッド A がそのレコードを削除し、同じキーフィールドでシグニチャ 1 の新しいレコードを作成します。その後スレッド B が、検索したレコードを変更しますが、それはすでに削除されています。モジュールは、スレッド B が検索したレコードのキーフィールドとシグニチャをデータ格納内のレコードと比較し、両者が同じなので変更を行います。しかし、これらのレコードは実際は同じものではないので、このような変更の試行は、本来は衝突とされるべきものです。
Solaris DHCP で提供される ds_SUNWfiles.so と ds_SUNWbinfiles.so モジュールは、こういった可能性を指摘します。これらのモジュールは、各レコードのシグニチャの一意性を確実にするために更新シグニチャを 2 つのフィールドに分割します。更新シグニチャの最初の 16 ビットフィールドに、ランダムに生成した数値を設定します。このフィールドは、設定後、レコード内で変更されません。シグニチャの下位 48 ビットフィールドには 1 が設定され、レコードが更新されるたびに 1 つずつ増分されます。
Solaris DHCP で提供されるモジュールは、レコードの更新における衝突を避けるためのアプローチの 1 つです。ユーザーは、これと似た方法を使用したり、独自の方法を考案することができます。
パブリックモジュールおよびコンテナはどちらも、アーキテクチャのアップグレードメカニズムが機能するためのバージョン番号を含んでいなければなりません。
パブリックモジュールの名前は、次の形式に従っていなければなりません。
ds_name.so.ver
ここで、name はモジュールの名前、ver はコンテナ形式のバージョン番号です。name は、ユーザーの組織に対応する、国際的に認知された識別子である接頭辞を使用する必要があります。たとえば、Sun Microsystems が提供するパブリックモジュールには、Sun の株式のティッカーシンボルである SUNW の接頭辞が付いていなくてはなりません。たとえば、NIS+ のパブリックモジュール名は ds_SUNWnisplus.so.1 となります。モジュール名にこのような識別子を含めることにより、パブリックモジュールディレクトリ /usr/lib/inet/dhcp/svc 内でパブリックモジュール名の衝突を避けることができます。
たとえば、会社名が Inet DataBase なら、モジュール名に ds_IDBtrees.so.1 を付けることができます。
管理インタフェースを通して管理者に表示されるコンテナの名前には、常に dhcptab と、DHCP ネットワークテーブルのドット形式の IP ネットワークアドレス (10.0.0.0 など) を含まなければなりません。
内部的に、データ格納コンテナの名前には、必要に応じてコンテナ形式の改訂番号を生成できるようにバージョン番号を含む必要があります。この名前付けのスキームでは、1 つのコンテナの複数のバージョンが同時に存在することが可能で、これはアーキテクチャのコンテナのバージョンアップグレードメカニズムが機能するために必要です。
コンテナに使用される名前は、その名前が一意であるために、国際的に認識できるトークンを含む必要があります。
たとえば、Solaris DHCP で提供される NIS+ のパブリックモジュールは、dhcptab コンテナを内部的には SUNWnisplus1_dhcptab として作成します。178.148.174.0 ネットワークテーブルのコンテナは SUNWnisplus1_178.148.174.0 になります。
会社名が Inet DataBase で、パブリックモジュールが ds_IDBtrees.so.1 であれば、コンテナに IDBtrees1_dhcptab および IDBtrees1_178.148.174.0 と名付けることができます。
Solaris DHCP サービスでは、DHCP コンテナのタイプとして dhcptab コンテナと DHCP ネットワークコンテナの 2 つが使用されます。
dhcptab コンテナには、dhcptab のマニュアルページに記述されている、DHCP 構成データが格納されています。DHCP サービスでは、dhcptab コンテナの 1 つのインスタンスのみが維持されます。
dhcptab レコードは、フレームワーク構成層とサービスプロバイダ層の間で内部構造 dt_rec_t によって渡されます。インクルードファイル /usr/include/dhcp_svc_public.h がこの構造を示します。
パブリックモジュールは、重複した dhcptab レコードが無いことを確実にしなければなりません。2 つのレコードが、同じキーフィールド値を持ってはなりません。
DHCP ネットワークコンテナには、dhcp_network のマニュアルページに記載されているように、複数の IP アドレスレコードが含まれます。これらのコンテナには、データ格納と、これらの IP アドレスが属しているネットワークのドット形式の IP アドレス (10.0.0.0 など) を示す名前が付けられます。DHCP ネットワークコンテナはいくつでも存在できますが、DHCP サービスによってサポートされる各ネットワークに対しては 1 つです。
DHCP ネットワークレコードは、フレームワーク構成層とサービスプロバイダ層の間で内部構造 dn_rec_t によって渡されます。インクルードファイル /usr/include/dhcp_svc_public.h がこの構造を示します。
パブリックモジュールは、重複したネットワークコンテナレコードが無いことを確実にしなければなりません。2 つのレコードが、同じキーフィールド値を持ってはなりません。
Solaris DHCP データアクセスアーキテクチャは、データ格納固有の構成データをパブリックモジュールに (従って、データ格納に) 渡すためのオプションの機能を提供します。この機能は、ASCII 文字列として実装されます。ASCII 文字列は、DHCP サービス管理インタフェース (dhcpconfig または dhcpmgr) を介してフレームワーク構成層に渡され、DHCP サーバーマシンに格納されます。詳細は、dhcpsvc.conf(4) のマニュアルページを参照してください。この文字列でどのような情報を渡すのかは、ユーザーが決定し、DHCP 管理者は管理ツールを介してこの文字列の値を提供します。この文字列は、たとえば、データベースへのログインに必要なユーザー名とパスワードなどを含むことができます。
DHCP 管理者から情報を得るには、適切なダイアログを表示するために JavaBeansTM コンポーネントを作成する必要があります。この情報は、その後単一の ASCII 文字列として管理インタフェースに渡されます。この ASCII 文字列トークンの形式は、デバッグを容易にするために文書化されていなければなりません。この機能をサポートするためのパブリックモジュールは 第 3 章「サービスプロバイダ層の API」で記述される configure() 関数を実装し、エクスポートする必要があります。
このアーキテクチャでは、ASCII 文字列は暗号化されません。クリアテキストで /etc/inet/dhcpsvc.conf ファイルに保管されます。暗号化された情報が必要な場合は、フレームワーク構成層に渡す前にビーンは情報を暗号化する必要があります。
コンテナバージョンのアップグレードにユーザーが関与する必要はありません。このアーキテクチャでは、パブリックモジュールとデータ格納コンテナの名前付けのガイドラインに従っている限り、異なるコンテナバージョンの共存を確立しているからです。管理ツールはアーキテクチャのこの機能を使用して、DHCP 管理者がコンテナのバージョンアップグレードを自動的に行えるようにします。
コンテナ形式のバージョンは、インストールによって (Solaris DHCP をアップグレードするとき)、または最初の DHCP サービス構成時の管理インタフェースを通して、フレームワーク構成層の構成ファイルに自動的に設定されます。新しいコンテナバージョンを含むパブリックモジュールの新しいバージョンをインストールしようとすると、新しいバージョンを管理インタフェースが自動的に検出し、パブリックモジュールのバージョンをアップグレードするかどうかを管理者にたずねます。アップグレードは延期することもできます。DHCP サービスは、管理者がパブリックモジュールをアップグレードするまで、元のバージョンのパブリックモジュールでの動作を継続します。
DHCP サービスの構成機能は、dhcpmgr および dhcpconfig 構成ツールによりシステム管理者に提供されます。モジュールをツールのユーザーから使用できるようにし、彼らが基盤となるデータサービスの構成を行えるようにしたい場合は、ビーンと呼ばれる JavaBeans コンポーネントをパブリックモジュールに対して提供する必要があります。
このビーンは、dhcpsvc.conf 内の PATH 変数と、オプションとして RESOURCE_CONFIG 変数を設定するために必要なコンテキストをパブリックモジュールに提供します。
dhcpmgr ツールは、com/sun/dhcpmgr/client/DSModule というインタフェースを提供します。このインタフェースは、パブリックモジュール管理ビーンが実装する必要のある API 関数を定義します。
DSModule インタフェースは、dhcpmgr.jar ファイルに含まれています。このインタフェースに対応したビーンをコンパイルするためには、/usr/sadm/admin/dhcpmgr/dhcpmgr.jar を javac のクラスパスに追加する必要があります。たとえば、myModule.java という名前のビーンには、次のように入力します。
javac -classpath /usr/sadm/admin/dhcpmgr/dhcpmgr.jar myModule.java
abstract java.awt.Component getComponent()
DHCP 構成ウィザードのウィザードステップの 1 つとして表示されるコンポーネントを返します。返されるコンポーネントは、構成時にユーザーから提供されたデータ格納固有のデータの取得に使用される GUI コンポーネントが含まれているパネルです。構成データそのものは、getPath() および getAdditional() メソッドへの呼び出しの結果としてウィザードに返されます。詳細は、getPath()と getAdditional()を参照してください。
abstract java.lang.String getDescription()
DHCP 構成ウィザードがデータ格納選択のリストにデータ格納を追加するときに使用する説明文を返します。たとえば、ds_SUNWfiles.so パブリックモジュールの管理ビーンは、説明として「Text files」を返します。
abstract java.lang.String getPath()
データ格納によって使用されるパス/位置 (フレームワーク構成層の構成ファイル /etc/inet/dhcpsvc.conf 内の PATH の値)、または設定されていない場合は NULL を返します。パス/位置の値は、管理ビーンのコンポーネントとの対話の中でユーザーが提供する必要があります。データ格納構成データの受け渡しを参照してください。
abstract java.lang.String getAdditional()
フレームワーク構成層の構成ファイル /etc/inet/dhcpsvc.conf 内のその他のデータ格納固有の情報 (RESOURCE_CONFIG などの情報) を返します。このメソッドから返される値は、ほとんど、管理ビーンのコンポーネントとの対話の中でユーザーが提供するものです。データ格納構成データの受け渡しを参照してください。
パブリックモジュールの管理ビーンは、次のパッケージングの用件に適合している必要があります。
パブリックモジュールの管理ビーンは、JAR ファイルとしてアーカイブされなければなりません。JAR ファイルの名前は、パブリックモジュールの名前と .jar 接尾辞から構成されていなければなりません。たとえば、ds_SUNWfiles.so パブリックモジュール内のパブリックモジュール管理ビーンの名前は SUNWfiles.jar になります。
JAR ファイルには、ビーンのクラスを識別する指標が含まれていなければなりません。たとえば、SUNWfiles.jar という JAR ファイルの指標には、次の行が含まれます。
Name: com/sun/dhcpmgr/client/SUNWfiles/SUNWfiles.class
Java-Bean: True
com/sun/dhcpmgr/client/SUNWfiles/SUNWfiles.class クラスは、com/sun/dhcpmgr/client/DSModule インタフェースを実装する JavaTM クラスです。