Solaris OS ネットワーキング -- マジックの種明かしSunay Tripathi (上級スタッフエンジニア、Solaris Core Technology Group)、2006 年 1 月 概要: この記事では Solaris 10 OS におけるネットワークの進歩だけでなく、旧リリースにおけるネットワークの進化についても説明しています。 TCP、UDP、IP、デバイスドライバフレームワーク、パフォーマンス向けのチューニングなどのトピックを扱っています。 目次
1.0 背景Solaris 1.x オペレーティングシステムのネットワークスタックは BSD 形式で、BSD Reno 実装によく似ていました。 BSD スタックはローエンドマシンには適していましたが、ローエンドの顧客だけでなく、企業顧客のニーズも満たすために、Solaris OS は AT&T SVR4 アーキテクチャーに移行し、これが Solaris 2.x プラットフォームになりました。 Solaris 2.x OS では、ネットワークスタックが大きく変更され、BSD スタイルのスタックから STREAMS ベースのスタックへと変わりました。 STREAMS フレームワークは簡単なメッセージ受け渡しインタフェースを備えており、STREAMS モジュール間での柔軟なやり取りが可能でした。 STREAMS の内部および外部境界を使用することで、モジュールの開発者は、実装を複雑にすることなく、相互排他を実現できました。 STREAM の設定にはコストがかかりましたが、1 秒あたりの接続数は重要な基準ではなく、通常、長時間の接続が行われていました。 NFS や FPT などのように接続時間が長くなるほど、全体の接続時間を通して見れば、新しいストリームの設定コストは償却されます。 1990 年代後半、サーバーは、多数の CPU を実行する SMP ベースになっていきました。 ミッドエンドマシンからハイエンドマシンが NUMA 主体となったため、CPU の切り替え処理のコストが高くなりました。 STREAMS は設計上 CPU と密接に関係していないため、特定の接続のパケットがさまざまな CPU の間を移動します。 Solaris 製品が、STREAMS アーキテクチャーから離れる必要があることは明らかでした。 1990 年代後半は、World Wide Web が爆発的な広がりを見せた時期でもありました。 処理能力の増加に伴い、短時間の接続が多数発生し、接続の設定時間も同じく重要になりました。 Solaris 10 プラットフォームでは、ネットワークスタックがさらに変化して、コア部分 (ソケットレイヤー、TCP、UPD、IP、デバイスドライバなど) で IP クラシファイアと直列化キューを使用することで、接続の設定時間、スケーラビリティー、およびパケット処理コストの向上を実現しました。 ISV が追加機能を実装するために必要な柔軟性を提供するために、STREAMS アーキテクチャーは引き続き使用されています。 2.0 Solaris 10 OS のスタック新しいフレームワークとその主要なコンポーネントの動作の仕組みについて見ていきましょう。 Solaris 10 OS 以前は、スタックは STREAMS 境界とカーネル適応型の相互排他を使用してマルチスレッドに対処しています。 TCP は STREAMS QPAIR 境界を使用し、UDP は STREAMS QPAIR と PUTSHARED を使用し、IP は PERMOD 境界と PUTSHARED を使用します。また、相互排他で保護される各種の TCP、UDP、および IP グローバルデータ構造が使用されます。 スタックは、さまざまなシステムコール、ネットワークデバイスドライバの読み込み側の割り込み、またはデバイスドライバのワークスレッドを実行するユーザー側のスレッドと、STREAMS フレームワークのワークスレッドの両方によって実行されます。 現在の境界は、モジュール単位、プロトコルスタックレイヤー単位、または水平境界を提供します。 Solaris 9 より以前の STREAMS ベースのスタックでは、個々のプロトコルレイヤーに対して水平境界が提供されるため、パケットが複数の CPU 上で、プロトコルレイヤー間でキューイングされる複数のスレッドによって処理されることがありました。 この結果、コンテキストの切り替えが頻繁に行われ、接続固有のデータ構造について、データの局所性が低下します。 「FireEngine」方式は、すべてのプロトコルレイヤーを、完全にマルチスレッド化された 1 つの STREAMS モジュールにマージします。 マージされたモジュール内では、データ構造単位のロックではなく、「垂直境界」と呼ばれる CPU 単位の同期メカニズムが使用されます。 「垂直境界」は、「squeue」と呼ばれる直列化キュー抽象化オブジェクトを使用して実装されます。 各 squeue は CPU にバインドされ、各接続は、接続固有のデータ構造にとって必要な同期と相互排他を提供する squeue にバインドされます。 インバウンドパケットの接続 (またはコンテキスト) ルックアップは、パケットが IP に達すると同時に、境界の外側で、IP 接続クラシファイアを使用して行われます。 格付けに基づいて、接続構造が識別されます。 ルックアップは境界の外部で発生するため、接続の初期化時に垂直境界または「squeue」のインスタンスに接続をバインドし、バインド先の squeue でその接続のすべてのパケットを処理することで、キャッシュの局所性が向上します。 垂直境界とクラシファイアの詳細については、あとのセクションで説明します。 クラシファイアは、すべてのインバウンドおよびアウトバウンドパケットに必要な一連の関数呼び出しを格納するデータベースにもなります。 これにより、Solaris ネットワークスタックは、現在のメッセージ受け渡しインタフェースから、BSD スタイルの関数呼び出しインタフェースへと変わります。 接続のパケット処理用のオンザフライで作成される関数の文字列 (イベントリスト) が最終的な新しいフレームワークの基礎であり、ほかのモジュールや Sun 以外の高パフォーマンスモジュールがこのフレームワークに参加できます。
squeue により、常に 1 つのスレッドのみが特定の接続を処理するため、マージされた TCP/IP モジュール内の複数のスレッド (読み取り側と書き込み側) による TCP 接続構造へのアクセスが直列化されます。 これは STREAMS QPAIR 境界に似ていますが、モジュールインスタンスを保護するだけでなく、IP から 垂直境界や squeue 自体は、パケットの直列化とデータ構造の相互排他を提供するだけですが、CPU 単位の境界を作成し、CPU 処理の割り込みに接続されたインスタンスに接続をバインドすることによって、データの局所性を高めることができます。 接続単位の境界または CPU 単位の境界という選択肢がありました。つまり、接続ごとのインスタンスまたは CPU ごとのインスタンスという選択肢です。 接続単位の境界に伴うオーバーヘッドとスレッドの競合によりパフォーマンスが低下することを考慮して、CPU 単位のインスタンスが採用されました。 CPU 単位のインスタンスの場合、接続構造をキューイングして処理する方法と、キューイングするのはパケットだけで、接続構造のポインタをパケットに格納するという方法が考えられました。 前者の方法の場合、接続用のパケットが絶えず到着する状況では、処理しきれなくなるおそれがあります。 このような状況を回避するためのオーバーヘッドは、パフォーマンスの低下をもたらしました。 パケットのキューイングでは順序が守られ、処理も非常に簡単なため、FireEngine ではこの方法が採用されました。 前述のように、各接続インスタンスは 1 つの squeue に割り当てられ、垂直境界の中でのみ処理されます。 squeue は一度に 1 つのスレッドによって処理されるため、境界内で特定の接続を処理するのに使用されるすべてのデータ構造は、ロックせずにアクセスできます。 この結果、接続メタデータ、パケットメタデータ、およびパケットペイロードデータのアクセスの、CPU とスレッドコンテキストのデータの局所性が向上します。 加えて、デバイス単位のドライバワークスレッド方式を使用せずに済みます。この方式では、システム全体のリソース問題を解決するのは困難です。また、新たな方針のアルゴリズムを実装して、ネットワークインタフェースのスループットおよびシステムスループットに基づいて、特定のネットワークインタフェースを適切に処理できます (たとえば、接続単位のパケット処理を CPU のグループにファンアウトします)。 squeue に入るスレッドは、すぐにパケットを処理することがあります。あるいは、それをキューイングして、あとで別のスレッドまたはワークスレッドで処理することもあります。 その選択は、squeue のエントリポイントと直列化の状態に依存します。 即時処理は、同じ squeue に別のスレッドが入っていない場合にのみ可能です。 squeue は、次の抽象化オブジェクトで表されます。
typedef struct squeue_s {
int_t sq_flag; /* Flags tells squeue status */
kmutex_t sq_lock; /* Lock to protect the flag etc */
mblk_t *sq_first; /* First Packet */
mblk_t *sq_last; /* Last Packet */
thread_t sq_worker; /* the worker thread for squeue */
} squeue_t;
squeue は、コアやハイパースレッドなど、H/W 実行パイプラインを基準に作成されることに注意してください。 直列化キュー (および H/W 実行パイプライン) のスタック処理は、一度に 1 つのスレッドに限られますが、新しいスタックがメモリーや垂直境界内のロックなどのリソースを待たなくて済むため、実際にパフォーマンスが改善されます。 また、複数のカーネルスレッドが H/W 実行パイプラインを時間共有する方が、1 つのスレッドだけが割り込みを受けずに実行するより、オーバーヘッドを伴います。
ワークスレッドは、常にキュー全体をドレインできます。 適切なドレインモデルの選択は、非常に複雑です。 次のいずれかが考えられます。
これらのオプションは、読み取りスレッドと書き込みスレッドに個別に適用できます。 通常、割り込みスレッドによるドレインは常に期限付きの「ドレインと処理」であり、これに対して書き込みスレッドは、「自分のパケットを処理」または期限付きの「処理とドレイン」のいずれかです。 Solaris 10 リリースでは、書き込みスレッドの動作はチューニング可能な変数で指定され、デフォルトは「自分のパケットを処理」ですが、読み取り側は「期限付きの処理とドレイン」に固定されています。 これとは別に、ワークスレッドの通知は検討を要する重要なオプションです。 パケットの到着率が低く、スレッドが自分のパケットをキューイングすることが設定されている場合、実行する作業があれば、入力スレッドが squeue の処理を終了すると同時に、ワークスレッドの実行を許可する必要があります。 一方、パケットの到着率が高い場合は、ワークスレッドを起動するのを遅らせて、ドレインを完了後すぐにパケットが到着して割り込みが発生することを期待する方が望ましいことがあります。 パケットの到着率が高い状態でワークスレッドをすぐに起動すると、ワークスレッドと割り込みスレッドの間で不要な競合が生じます。 Solaris 10 OS のデフォルト設定では、ワークスレッドが遅れて起動するようになっています。 利用可能なサーバーで最初に試したところ、10 分遅らせてワークスレッドを起動したときに最適な結果が得られました。 squeue に要求を入れるには、squeue 単位のロックでキューの状態を保護する必要がありますが、CPU に分散されており、その時間も短いため、スケーラビリティーの問題は生じません。 最適化も利用しており、これによって、squeue 処理における単一スレッドのセマンティクスを保持したまま、コンテキストの切り替えを回避できます。 システム内の CPU ごとに squeue のインスタンスを作成し、その CPU にワークスレッドをバインドします。 そして、各接続は、特定の squeue、さらに特定の CPU にバインドされます。 squeue と CPU のバインドは変更できますが、squeue を保護する意味で、接続と squeue のバインドを変更することはできません。 マージされた TCP/IP の場合、垂直境界が各接続の TCP 状態を保護します。 各接続が使用する squeue のインスタンスは、アウトバウンド接続の場合は「オープン」、「バインド」、または「接続」時に選択され、インバウンド接続の場合は「イーガー接続作成時」に選択されます。 squeue インスタンスの選択は、システム内の CPU と NIC の相対速度で決まります。 2 つの場合があります。
Solaris 10 OS の場合、NIC が CPU より高速であるか低速であるかの判断は、システム管理者が、グローバル変数
squeue_t *squeue_create(squeue_t *, uint32_t, processorid_t, void (*)(), \
void *, clock_t, pri_t);
void squeue_bind(squeue_t *, processorid_t);
void squeue_unbind(squeue_t *);
void squeue_enter(squeue_t *, mblk_t *, void (*)(), void *);
void squeue_fill(squeue_t *, mblk_t *, void (*)(), void *);
IP 接続のファンアウトメカニズムは、3 つのハッシュテーブルから成ります。
ルックアップの一部として、接続構造 (すべての接続情報のスーパーセット) が返されます。 この接続情報は
typedef struct conn_s {
kmutex_t conn_lock; /* Lock for conn_ref */
uint32_t conn_ref; /* Reference counter */
uint32_t conn_flags; /* Flags */
struct ill_s *conn_ill; /* The ill packets are coming on */
struct ire_s *conn_ire; /* ire cache for outbound packets */
tcp_t *conn_tcp; /* Pointer to tcp struct */
void *conn_ulp /* Pointer for upper layer*/
edesc_pf conn_send; /* Function to call on read side */
edesc_pf conn_recv; /* Function to call on write side */
squeue_t *conn_sqp; /* Squeue for processing */
/* Address and Ports */
struct {
in6_addr_t connua_laddr; /* Local address */
in6_addr_t connua_faddr; /* Remote address. */
} connua_v6addr;
#define conn_src V4_PART_OF_V6(connua_v6addr.connua_laddr)
#define conn_rem V4_PART_OF_V6(connua_v6addr.connua_faddr)
#define conn_srcv6 connua_v6addr.connua_laddr
#define conn_remv6 connua_v6addr.connua_faddr
union {
/* Used for classifier match performance */
uint32_t conn_ports2;
struct {
in_port_t tcpu_fport; /* Remote port */
in_port_t tcpu_lport; /* Local port */
} tcpu_ports;
} u_port;
#define conn_fport u_port.tcpu_ports.tcpu_fport
#define conn_lport u_port.tcpu_ports.tcpu_lport
#define conn_ports u_port.conn_ports2
uint8_t conn_protocol; /* protocol type */
kcondvar_t conn_cv;
} conn_t;
ここで注目すべきメンバーは、squeue、または垂直境界へのポインタです。 ルックアップは境界の外部で行われ、パケットは、接続先の squeue で処理またはキューイングされます。 また、
また、接続ファンアウトメカニズムには、 IP クラシファイア API は、次のようになります。
conn_t *ipcl_conn_create(uint32_t type, int sleep);
void ipcl_conn_destroy(conn_t *connp);
int ipcl_proto_insert(conn_t *connp, uint8_t protocol);
int ipcl_proto_insert_v6(conn_t *connp, uint8_t protocol);
conn_t *ipcl_proto_classify(uint8_t protocol);
int *ipcl_bind_insert(conn_t *connp, uint8_t protocol, ipaddr_t src,
uint16_t lport);
int *ipcl_bind_insert_v6(conn_t *connp, uint8_t protocol,
const in6_addr_t * src, uint16_t lport);
int *ipcl_conn_insert(conn_t *connp, uint8_t protocol, ipaddr_t src,
ipaddr_t dst, uint32_t ports);
int *ipcl_conn_insert_v6(conn_t *connp, uint8_t protocol,
in6_addr_t *src, in6_addr_t *dst, uint32_t ports);
void ipcl_hash_remove(conn_t *connp);
conn_t *ipcl_classify_v4(mblk_t *mp);
conn_t *ipcl_classify_v6(mblk_t *mp);
conn_t *ipcl_classify(mblk_t *mp);
関数の名前は、その内容をそのまま表しています。
垂直境界によって実現される CPU 単位の直列化を除けば、スタックは完全にマルチスレッド化されているため、参照ベースの方式を使用して、必要なときに接続インスタンスを使用できるようにしています。 参照カウントは 確立された TCP 接続の場合は、3 つの参照があります。 各プロトコルレイヤーは、インスタンス (TCP と IP について 1 つずつ) への参照を持ちます。また、クラシファイア自体も確立された接続であるため、参照を持ちます。 パケットが接続に到着し、クラシファイアが接続インスタンスを検索するたびに、新たな参照が発生しますが、プロトコルレイヤーがそのパケットの処理を終了すると廃棄されます。 同様に、接続インスタンス上で実行するタイマーは、タイマーが起動したときにいつでもインスタンスが機能するように参照を備えています。 接続インスタンスに関連付けられているメモリーは、最後の参照が廃棄されると解放されます。 3.0 TCP
Solaris 10 OS における TCP の扱いは、これまでのリリースと同じです。つまり、TCP はクローンデバイスのように見えますが、実際には、TCP および IP コードが 1 つの D_MP STREAMS モジュールにマージされた複合物です。 マージされた TCP/IP モジュールのオープンとクローズの STREAMS エントリポイントは、IP のエントリポイント、つまり
TCP の操作部分は、図 1 に示されているように、
図 1 垂直境界が使用する TCP エントリポイント: tcp_input - All inbound data packets and control messages tcp_output - All outbound data packets and control messages tcp_close_output - On user close tcp_timewait_output - timewait expiry tcp_rsrv_input - Flow control relief on read side tcp_timer - All tcp timers
FireEngine では、TCP と IP 間のインタフェースが、制御パスとデータパスの両方とも、STREAMS ベースのメッセージ受け渡しインタフェースから関数呼び出しベースのインタフェースへと変更されています。 アウトバウンド側では、垂直境界の内部にいながら、TCP は
同様に、制御メッセージも関数引数として直接渡されます。 基本的なプロトコル処理コードは変更されていません。 一般的なソケット呼び出し、およびフレームワークとのやり取りについて見てみましょう。
TCP のソケットオープンまたは
tcp_connect における変更は、tcp_bind に似ています。 完全な bind() 要求は TPI メッセージとして準備され、関数引数として ip_bind_v{4, 6} に渡されます。 IP はクラシファイアを呼び出し、接続されたハッシュテーブルに接続を挿入します。 TCP 内の conn_ hash テーブルは使用されません。
このパスは、tcp_bind の一部です。 tcp_bind はローカルのバインド TPI メッセージを準備し、それを関数引数として ip_bind_v{4, 6} に渡します。 IP はクラシファイアを呼び出し、バインドハッシュテーブルに接続を挿入します。 TCP の待機ハッシュテーブルはもはや存在しません。
Solaris 10 以前のリリースにおける accept 実装では、リスナーコンテキスト内での接続設定の処理が多く行われていました。 3 ウェイハンドシェークはリスナーの境界で完了し、接続の指示がリスナーの STREAM に送信されました。 受け入れを実行するのに必要なメッセージがリスナーの STREAM に送信され、リスナーは、T_CONN_RES メッセージを TCP に送信する時点から、sockfs が肯定応答を受信するまで、シングルスレッド化されていました。 Solaris 10 以前のリリースでは、接続の到着率が高い場合、新しい接続を受け入れるスタックの能力は、大きく低下しました。
さらに、TCP のオーバーヘッドが加わると、受け入れ率の低下を招きました。
FireEngine モデルでは、SYN パケットが到着すると同時にその境界内で「イーガー」接続を確立することで (着信接続は、受け入れが完了するまで「イーガー」と呼ばれます)、そのパケットは常に正しい接続先に向かいます。 その結果、TCP グローバルキューを完全に除去することが可能です。 接続指示は引き続きリスナーの STREAM に送信されますが、新しく作成されたアクセプタの STREAM で受け入れが発生し (このため、この STREAM のデータ構造を割り当てる必要がありません)、肯定応答をアクセプタの STREAM に送信できます。 そのため、 新しい着信接続 (イーガー) が存在するのはそのリスナーがあるためだけであり、イーガーもリスナーも、イーガーがリセットを受信したりリスナーが閉じることによって受け入れ処理中の任意の時点で消滅する可能性があるため、新しいモデルは慎重に実装されました。
リスナーが閉じた場合でも、リスナーへのイーガー参照が常に有効となるように、リスナーに参照を配置することによって、イーガー接続は開始します。 3 ウェイハンドシェークの完了後に接続指示を送信する必要がある場合、イーガーは、リセットを受信して閉じても参照が引き続き有効となるように、自身に参照を配置します。 イーガーは、接続指示メッセージの一部として自身へのポインタを送信しますが、これは、リスナーが閉じていないことを確認してから、リスナーの STREAM を利用して送信されます。 クローズするキューと TCP への参照が切り離されたため、TCP 内のクローズ処理は、参照カウントがゼロになるまで待つ必要がなくなりました。 クローズするキューへのすべての参照がなくなると同時に、クローズは終了します。 TCP データ構造自体は、ほとんどの場合、切り離された TCP として引き続き存在できます。 TCP への最後の参照が解除されると、TCP データ構造が解放されます。
ユーザーが起動するクローズは、ストリームのみを閉じます。 基になる TCP 構造は、引き続き存在します。 TCP は、すべてのユーザーデータの転送後にピアとの TCP は、IRE にアクセスできるのであれば、ほとんどの場合、アウトバウンドパケットを送信するのに IP を呼び出す必要もありません。 マージされた TCP/IP では、接続用にキャッシュされた IRE にアクセスできるという利点があり、TCP は IRE 内の情報に基づいて、データをリンクレイヤードライバに直接プッシュできます。 FireEngine の処理は前述のとおりです。
TCP Fusion は、Solaris 10 OS におけるループバック TCP 接続用のプロトコルレスデータパスです。 2 つのローカル TCP エンドポイントの融合は、接続の確立時に起こります。 デフォルトでは、すべてのループバック TCP 接続が融合されます。 この動作は、チューニング可能なシステム変数
融合が失敗した場合は通常の TCP データパスを使用し、成功した場合は、両方のエンドポイントが送信パスとして
同期 STREAMS が有効な場合は、後者のパスが取られます。 モジュールの挿入または削除が原因で TCP モジュールの上位に
TCP Fusion 内のロックは、squeue と相互排他の 同期ストリームモードでの TCP Fusion において、小規模な書き込みフロー制御の速度制限は、それぞれ異なる制限に設定されている、受信バッファーのサイズとデータブロックの数を確認することによって実現されます。 これは、累積サイズのチェックがデータブロックカウントのチェックより優先される標準の STREAMS フロー制御とは異なります (STREAMS キューの高位境界値は、通常、バイトを表します)。 各キューイングによって、受信プロセスに通知が送られます。データブロックの増加は受信側が低速であることを表しており、送信側は、システムリソースをこれ以上無駄にしないために、できるだけ早い段階でブロックまたは通知される必要があります。 実際これは、システム内の未処理のセグメント数を制限することに相当します。
キューイング可能なデータブロックの最小数のデフォルト値は 8 です。この値は、チューニング可能なシステム変数 4.0 UDPSolaris 10 OS では、フレームワークの改善とは別に、スタック内での UDP パケットの移動に変更が加えられました。 プロジェクトの内部コード名は「Yosemite」でした。 Solaris 10 リリース以前の UDP 処理コストは、パケット単位の処理コストとバイト単位の処理コストに均等に分かれていました。 通常、パケット処理コストは、STREAMS、ストリームヘッド処理、およびスタックとドライバ内でのパケット廃棄によるものでした。 バイト単位の処理コストは、H/W チェックサムの欠如と、ネットワークスタック全体をとおしての最適化されていないコード分岐によるものでした。 UDP は信頼性が低いと考えられていますが、ローカルエリアネットワークは信頼性が非常に高まってきており、アプリケーションは LAN 環境内でのパケットロスがないと想定する傾向にあります。 この想定はほぼ正しいのですが、Solaris 10 以前のバージョンでは、スタックは UDP オーバーロードの処理に関してあまり効率的ではなく、スタック自体の中でパケットを廃棄する傾向がありました。インバウンドでは、受信パス全体で複数のレイヤーでパケットが廃棄されていました。 UDP の場合、パケットが廃棄されるもっとも一般的で明らかな場所は、パケットをキューイングするリソースが欠如している IP レイヤーでした。 パケットの廃棄が発生するもう 1 つの重要で明らかな場所は、ネットワークアダプタレイヤーです。 この種の廃棄は、通常、マシンが着信率が高いパケットを処理しているときに発生します。
UDP
これは、IP と同じ保護ドメインのもとで実行する、完全なマルチスレッド UDP モジュールです。 このモジュールにより、トランスポート (UDP) が上下のレイヤーと密接に統合されます。 また、
エンドポイントの状態を変更する関数を実行する場合、UDP ではエンドポイント単位での排他的処理が必要です。 Solaris 10 モデルは、STREAMS に依存しない内部境界を使用して前述の同期を実現します。その詳細を次に示します。
上位または下位から UDP に入るには、
これをサポートするために、新しい UDP モデルは、UDP MT HOT モードおよび UDP SQUEUE モードという、2 つの操作モードを取り入れています。 UDP MT HOT モードでは、複数のスレッドが同時に UDP エンドポイントに入る可能性があります。 これは、標準データの送受信に使用され、putshared STREAMS エントリポイントに似ています。 制御操作とその他の特殊なケースでは
安定したモードにある間、UDP はエンドポイントで動作するスレッドの数を追跡します。 UDP と IP は同じ保護ドメインで実行しますが、これらは依然として別々の STREAMS モジュールです。 このため、STREAMS の plumb はそのまま保持され、UDP モジュールインスタンスは常に IP 上にプッシュされます。 これは、すべての UDP エンドポイントについて余分なオープンとクローズを引き起こしますが、ストリームに I POP を発行して IP9 に直接アクセスするなど、特定の処理をこのような plumb ジオメトリに依存して行うアプリケーションに対して、下位互換性を提供します。 実際の UDP 処理は、IP インスタンス内で行われます。 UDP モジュールインスタンスは、エンドポイントに関する状態を持っているわけではなく、ダミーモジュールとして動作するに過ぎません。その目的は、STREAMS plumb の外観を変えないことです。 Solaris 10 プラットフォームでは、次の plumb モードを使用できます。
これらのモードは、IP と UDP の間の中間モジュールがサポートされていないことを意味しています。IP とトランスポートモジュールの間のレイヤー間通信のセマンティクスは非公開なので、実際、Solaris テクノロジでは、このようなシナリオをこれまでサポートしてきませんでした。
トランスポートモジュールの場合、 同期 STREAMS は、メッセージの受け渡しと処理を目的とする、従来の STREAMS インタフェースの拡張機能です。 当初は、コピーとチェックサムを組み合わせた機能の一部として追加されました。 この機能により、モジュールまたはドライバのエントリポイントを、ユーザーの I/O 要求に関して、同期形式で呼び出すことができます。 従来の STREAMS では、このような要求に対して、ストリームヘッドが同期バリアーです。 同期 STREAMS は、このバリアーを、ストリームヘッドから下のモジュールへと移動するメカニズムを提供します。
同期 STREAMS の TCP 実装は、さまざまな要因で、Solaris 10 より以前のリリースでは複雑でした。 大きな要因は、チェックサムと
これに対して、Solaris 10 OS の場合、TCP は
データが到着するたびに、トランスポートモジュールは、アプリケーションによるデータの取得をスケジュールします。 読み取り処理の際にアプリケーションがブロックされている場合 (スリープ状態) は、ブロックが解除されて、実行が再開されます。 これは、ストリーム上で
アプリケーションは、読み取りイベントが発生するまで 読み取り処理の一部として、トランスポートモジュールは、読み取り側の同期 STREAMS エントリポイントからデータを返すことにより、アプリケーションにデータを配信します。 ループバック TCP の場合、同期 STREAM の読み取りエントリポイントは、その受信キューの内容全体 (バイトストリーム) をストリームヘッドに返します。残りのデータは、次の読み取りを待つストリームヘッドでキューイングされます。 UDP の場合、読み取りエントリポイントは、一度に 1 つのメッセージ (データグラム) のみを返します。
デフォルトでは、
(ソケットエンドポイントでは I INSERT または I REMOVE
フォールバックが要求される場合、 5.0 IP前述のように、すべてのトランスポートレイヤーは、STREAMS モジュールと同様に、完全にマルチスレッド化され、擬似デバイスドライバとして動作する IP モジュールにマージされています。 IP における主要な変更は、IP クライアント機能の削除と、インバウンドパケットストリームの多重化でした。 新しい IP クラシファイア (依然として IP モジュールの一部) の役割は、インバウンドパケットを適切な接続インスタンスに分類することです。 IP モジュールは、引き続き、ネットワークレイヤープロトコルの処理と、ネットワークインタフェースの plumb および管理を扱います。 新しいスタック内でのネットワークインタフェース、マルチパス、およびマルチキャストの plumb の動作の仕組みついて見てみましょう。
plumb は、IP、ARP、およびデバイスドライバ間でのメッセージ交換に関係する一連の長い処理です。 IOCTL セットの大部分は、通常、plumb 処理に関係します。 普通のモデルでは、これらの IOCTL を ILL (IP Lower Level) ごとに 1 つずつ直列化します。 たとえば、 さらにきめの細かい方法を使用し、IIL ごとではなく、IPIF ごとに処理を直列化するという方法も考えられます。 この方法は、多くの IPIF が ILL 上でホストされていて、異なる IPIF 上の処理が相互に干渉しない場合のみ効果があります。 さらに、標準の Solaris MT 手法を使用して、すべての IOCTL を完全にマルチスレッド化するという方法も考えられます。 しかし、この方法は必要以上に複雑で、それほどの付加価値はありません。 待機、およびドライバやほかのモジュールとのメッセージ交換が含まれる plumb シーケンス全体をとおしてロックを保持することは困難です。 純粋な反復的でない制御処理が行われるため、IPIF 上に複数の IOCTL セットを同時に許可することは、パフォーマンス的にも機能的にもメリットはありません。 ブロードキャスト IRE は、IPIF 単位ではなく IIL 単位に作成されます。 このため、IIL 上で複数の IPIF を同時に起動しようとすると、IRE 作成ロジックが非常に複雑になります。 一方、IIL 単位での plumb 処理の直列化は、既存の IP コードベースに簡単に役立ちます。 plumb の中で、IP はデバイスドライバおよび ARP とメッセージを交換します。 基になるデバイスドライバから受信したメッセージも、IP で排他的に処理されます。 書き込み側と読み取り側の処理の間で相互排他を提供する中で、putnext では標準の相互排他ロックを保持することはできないため、この方法は便利です。 全排他的な PERMOD syncq ではなく、ILL 単位の直列化キューを使用することで、この効果は簡単に実現できます。
IPMP 処理はすべて、IPMP グループの概念に基づいて行われます。 フェイルオーバー処理とフェイルバック処理は、通常は同じ IPMP グループに含まれる 2 つの IIL の間で行われます。 IPIF と ILM は、IIL 間を移動します。 これには、発信元 ILL の下位への移動が含まれ、場合によっては送信先 ILL の上位への移動が含まれます。 IIL の上下への移動は、ブロードキャスト IRE に影響します。 ブロードキャスト IRE は、ブロードキャストパケットが重複して受信されないように、IPMP グループごとにグループ化する必要があります。 このため、ブロードキャスト IRE の操作は、IPMP グループのすべてのメンバーに影響します。
マルチキャストジョインは、ILG 構造と ILM 構造の両方で動作します。 マルチキャストジョインを実行しようとする、IPC (ソケット) 上で動作している複数のスレッドは、ILG で動作するときには同期をとる必要があります。 マルチキャストジョインを実行しようとする、異なる IPC (ソケットエンドポイント) 上で動作している可能性がある複数のスレッドは、最終的に ILM を同時に操作する場合があり、ILM へのアクセスについて同期をとる必要があります。 両方の場合とも、標準的な Solaris MT 手法に従います。 これまでに述べた plumb、IPMP、およびマルチキャストのすべて考慮した場合、その共通点は、IPMP グループ単位ですべての排他処理を直列化することです。 IPMP が有効でない場合は、 6.0 Solaris 10 デバイスドライバフレームワークSolaris 10 OS 以前のネットワークデバイスドライバの実装方法と、これを新しい Solaris 10 スタックでなぜ変更しなければならなかったかについて、簡単に説明します。 6.1 GLDv2 およびモノリシックドライバ (Solaris 9 以前のリリース) Solaris 10 より以前のリリースでは、ネットワークスタックは、通常は 2 つの方法のいずれかで実装される DLPI1 プロバイダを経由します。 次の図 (図 2) は、いわゆるモノリシック Data Link Provider Interface (DLPI) ドライバに基づくスタックと、Generic LAN Driver (GLDv2) モジュールを利用するドライバに基づくスタックを示しています。
図 2 GLDv2 モジュールは、基本的にライブラリとして動作します。 クライアントは、引き続きデバイスにバインドされているドライバインスタンスとやり取りしますが、DLPI プロトコル処理は GLDv2 モジュールを呼び出すことによって行われ、これが次にドライバを呼び出してハードウェアにアクセスします。 GLD モジュールを使用することで、ドライバの開発者に、ほとんどが汎用的な大量の DLPI プロトコル処理を再実装しなくて済むという明らかな利点がもたらされます。 802.1q 仮想 LAN (VLAN) などのレイヤー 2 (データリンク) 機能も主に GLD モジュールに実装できるため、すべてのドライバでこれを利用できます。 ただし、802.3ad リンク集積体 (トランキング) など、ネットワークインタフェースとデバイスが 1 対 1 で対応していない機能を実装する場合、アーキテクチャーには問題が生じます。 GLDv2 およびモノリシックドライバは両方とも DLPI メッセージに依存し、STREAMS フレームワークを通じて上位レイヤーと通信します。 このメカニズムは、リンク集積体や 10Gb NIC ではあまり効率的ではありませんでした。 新しいスタックでは、データの局所性を実現し、スタックがきめ細かくデバイスドライバを制御して割り込みを処理できる、優れたメカニズムが必要でした。 Solaris 10 ソフトウェアには、新しいスタックとともに、GLDv3 (内部名「project Nemo」) という新しいデバイスドライバフレームワークが導入されました。 主要なデバイスドライバの大部分はこのフレームワークに移植され、今後のすべてのデバイスドライバや 10Gb デバイスドライバは、このフレームワークに基づくことになります。 このフレームワークには、(外部の非 IP モジュールが引き続き動作できるように) 下位互換性用に、STREAMS ベースの DLPI レイヤーも用意されています。 GLDv3 アーキテクチャーは、ネットワークスタックのレイヤー 2 を仮想化します。 ネットワークインタフェースとデバイスの間に、1 対 1 の関係はもはや存在しません。 次の図 (図 3) は、MAC サービス モジュール (MAC) に登録された複数のデバイスを示しています。 また、DLPI を通じてデータリンクドライバ (DLD) と通信する従来のクライアントと、カーネルベースで、データリンクサービスモジュール (DSL) に対して関数呼び出しを直接行うクライアントも示されています。
図 3 6.2.1 GLDv3 ドライバ
GLDv3 ドライバは、GLD ドライバに似ています。 ドライバは、misc/mac. および misc/dld. の依存関係にリンクしている必要があります。 次の構造のインスタンスへのポインタを指定して
typedef struct mac {
const char *m_ident;
mac_ext_t *m_extp;
struct mac_impl *m_impl;
void *m_driver;
dev_info_t *m_dip;
uint_t m_port;
mac_info_t m_info;
mac_stat_t m_stat;
mac_start_t m_start;
mac_stop_t m_stop;
mac_promisc_t m_promisc;
mac_multicst_t m_multicst;
mac_unicst_t m_unicst;
mac_resources_t m_resources;
mac_ioctl_t m_ioctl;
mac_tx_t m_tx;
} mac_t;
この構造は登録の有効期間中存続する必要があり、たとえば、
この
typedef uint64_t (*mac_stat_t)(void *, mac_stat_t);
このエントリポイントは、
typedef int (*mac_start_t)(void *);
インタフェースが登録されたときにリセット/休止状態であったデバイスを、その状態から解除するために、このエントリポイントは呼び出されます。 この呼び出しが行われるまで、MAC モジュールが伝送用のパケットを送信することはなく、ドライバは受信用のパケットを送信できません。 この関数が正常終了すると、ゼロが返されます。 異常終了すると、該当の
typedef void (*mac_stop_t)(void *); このエントリポイントは、インタフェースの登録を解除できるように、デバイスを停止し、リセット/休止状態にします。 この呼び出しが行われると、MAC モジュールが伝送用のパケットを送信することはなく、この呼び出しが完了すると、ドライバは受信用のパケットを送信できません。
typedef int (*mac_promisc_t)(void *, boolean_t);
このエントリポイントは、デバイスの混在を設定するために使用されます。 2 番目の引数が
typedef int (*mac_multicst_t)(void *, boolean_t, const uint8_t *);
このエントリポイントは、デバイスがパケットを受信するマルチキャストアドレスのセットにアドレスを追加または削除するために使用されます。 2 番目の引数が
typedef int (*mac_unicst_t)(void *, const uint8_t *); このエントリポイントは、新しいデバイスユニキャストアドレスを設定するために使用されます。 この呼び出しが行われると、デバイスが休止モードの場合を除いて、新しいアドレスおよびメディアブロードキャストアドレスを持つパケットのみを受信します。
typedef void (*mac_resources_t)(void *, boolean_t); このエントリポイントは、ドライバが個々の受信リソースまたは Rx リングを登録することを要求するために呼び出されます。
typedef mblk_t *(*mac_tx_t)(void *, mblk_t *);
このエントリポイントは、デバイスが伝送用のパケットを送信するために使用されます。 2 番目の引数は、
typedef struct mac_info {
uint_t mi_media;
uint_t mi_sdu_min;
uint_t mi_sdu_max;
uint32_t mi_cksum;
uint32_t mi_poll;
boolean_t mi_stat[MAC_NSTAT];
uint_t mi_addr_length;
uint8_t mi_unicst_addr[MAXADDRLEN];
uint8_t mi_brdcst_addr[MAXADDRLEN];
} mac_info_t;
typedef enum {
MAC_STAT_IFSPEED = 0,
MAC_STAT_MULTIRCV,
MAC_STAT_BRDCSTRCV,
MAC_STAT_MULTIXMT,
MAC_STAT_BRDCSTXMT,
MAC_STAT_NORCVBUF,
MAC_STAT_IERRORS,
MAC_STAT_UNKNOWNS,
MAC_STAT_NOXMTBUF,
MAC_STAT_OERRORS,
MAC_STAT_COLLISIONS,
MAC_STAT_RBYTES,
MAC_STAT_IPACKETS,
MAC_STAT_OBYTES,
MAC_STAT_OPACKETS,
MAC_STAT_ALIGN_ERRORS,
MAC_STAT_FCS_ERRORS,
MAC_STAT_FIRST_COLLISIONS,
MAC_STAT_MULTI_COLLISIONS,
MAC_STAT_SQE_ERRORS,
MAC_STAT_DEFER_XMTS,
MAC_STAT_TX_LATE_COLLISIONS,
MAC_STAT_EX_COLLISIONS,
MAC_STAT_MACXMT_ERRORS,
MAC_STAT_CARRIER_ERRORS,
MAC_STAT_TOOLONG_ERRORS,
MAC_STAT_MACRCV_ERRORS,
MAC_STAT_XCVR_ADDR,
MAC_STAT_XCVR_ID,
MAC_STAT_XVCR_INUSE,
MAC_STAT_CAP_1000FDX,
MAC_STAT_CAP_1000HDX,
MAC_STAT_CAP_100FDX,
MAC_STAT_CAP_100HDX,
MAC_STAT_CAP_10FDX,
MAC_STAT_CAP_10HDX,
MAC_STAT_CAP_ASMPAUSE,
MAC_STAT_CAP_PAUSE,
MAC_STAT_CAP_AUTONEG,
MAC_STAT_ADV_CAP_1000FDX,
MAC_STAT_ADV_CAP_1000HDX,
MAC_STAT_ADV_CAP_100FDX,
MAC_STAT_ADV_CAP_100HDX,
MAC_STAT_ADV_CAP_10FDX,
MAC_STAT_ADV_CAP_10HDX,
MAC_STAT_ADV_CAP_ASMPAUSE,
MAC_STAT_ADV_CAP_PAUSE,
MAC_STAT_ADV_CAP_AUTONEG,
MAC_STAT_LP_CAP_1000FDX,
MAC_STAT_LP_CAP_1000HDX,
MAC_STAT_LP_CAP_100FDX,
MAC_STAT_LP_CAP_100HDX,
MAC_STAT_LP_CAP_10FDX,
MAC_STAT_LP_CAP_10HDX,
MAC_STAT_LP_CAP_ASMPAUSE,
MAC_STAT_LP_CAP_PAUSE,
MAC_STAT_LP_CAP_AUTONEG,
MAC_STAT_LINK_ASMPAUSE,
MAC_STAT_LINK_PAUSE,
MAC_STAT_LINK_AUTONEG,
MAC_STAT_LINK_DUPLEX,
MAC_STAT_LINK_STATE,
MAC_NSTAT /* must be the last entry */
} mac_stat_t;
マクロ 6.2.2 MAC サービス (MAC) モジュール いくつかの重要なドライバサポート関数を、次に示します。
extern mac_resource_handle_t mac_resource_add(mac_t *, mac_resource_t *); 各種のメンバーは、次のように定義されています。
typedef void (*mac_blank_t)(void *, time_t, uint_t);
typedef mblk_t *(*mac_poll_t)(void *, uint_t);
typedef enum {
MAC_RX_FIFO = 1
} mac_resource_type_t;
typedef struct mac_rx_fifo_s {
mac_resource_type_t mrf_type; /* MAC_RX_FIFO */
mac_blank_t mrf_blank;
mac_poll_t mrf_poll;
void *mrf_arg;
time_t mrf_normal_blank_time;
uint_t mrf_normal_pkt_cnt;
} mac_rx_fifo_t;
typedef union mac_resource_u {
mac_resource_type_t mr_type;
mac_rx_fifo_t mr_fifo;
} mac_resource_t;
この関数は、個々の受信リソース (一般には DMA 記述子のリングバッファー) を MAC モジュールに登録するために、
この
その他のフィールドの
割り込み率は、異なる引数を指定して
extern void mac_resource_update(mac_t *); 使用可能なリソースが変更された場合にドライバによって呼び出されます。
extern void mac_rx(mac_t *, mac_resource_handle_t, mblk_t *);
この関数は、 6.2.3 データリンクサービス (DLS) モジュール DLS モジュールは、DLPI に似たデータリンクサービスインタフェースを提供します。 DLPI で指定される STREAMS メッセージベースのインタフェースに対して、DLS インタフェースはカーネルレベルの関数インタフェースです。 このモジュールは、上位レイヤーがデータリンクサービスを作成および破棄するのに必要なインタフェースと、NIC を plumb および unplumb するのに必要なインタフェースも提供します。 GLDv3 ベースのデバイスドライバにおける NIC の plumb および unplumb は、以前の GLDv2 またはモノリシック DLPI デバイスドライバのときから変更されていません。 主要な変更は、直接呼出し、パケットチェーン、および NIC に対するきめ細かな制御が可能なデータパスにあります。 6.2.4 データリンクドライバ (DLD) データリンクドライバは、DLS および MAC モジュールが提供するインタフェースを使用する DLPI をサポートします。 ドライバは、制御ノードに渡される IOCTL を使用して構成されます。 これらの IOCTL が、個々の DLPI プロバイダノードを作成および破棄します。 このモジュールは、NIC を plumb/unplumb するのに必要な DLPI メッセージを扱い、GLDv3 に対応していないクライアント用に STREAMS を経由するデータパスについて、下位互換性を提供します。 GLDv3 フレームワークは、IEEE 802.3ad で定義されるリンク集積体をサポートします。 この機能を設計する上での主要な設計原則は、次のようなものでした。
GLDv3 のリンク集積体は、
図 4
GLDv3 Solaris 10 プラットフォームでは H/W チェックサムオフロード機能が改善され、ほとんどアプリケーションで全体のパフォーマンスが向上しました。 ある時期、16 ビットの 1 の補数チェックサムオフロードフレームワークが、Solaris ソフトウェアに存在していました。 これは当初、Solaris 2.6 OS のゼロコピー TCP/IP の要件として追加されたものですが、最近になるまで、ほかのプロトコルを処理できるように拡張されませんでした。 Solaris テクノロジでは、2 つのクラスのチェックサムオフロードを次のように定義しています。
現在の大部分のネットワークアダプタは、インタフェースにわずかな違いはありますが、いずれかのクラスのチェックサムオフロードをサポートするため、断片化されていない IPv4 のケース (ユニキャストまたはマルチキャスト) のサポートを追加することは、送信と受信の両方にとって重要ではありません。 IPv4/IPv6 上の TCP/UDP パケットについてチェックサム計算を処理できる、完全チェックサムネットワークアダプタはほとんどないため、IPv6 の場合はそれほど簡単ではありません。 断片化された IP の場合も、同様の制約があります。 送信時、チェックサムは断片化されていないデータグラムに適用されます。 アダプタがチェックサムオフロードをサポートするためには、最終的にチェックサムを計算し、回線上でフラグメントを送信する前に、すべての IP フラグメントをバッファリングできる (またはハードウェア内で断片化を実行できる) 必要があります。そのときまで、アウトバウンド IP フラグメントのチェックサムオフロードを実行することはできません。 これに対して、ほとんどの完全チェックサム (およびすべての部分チェックサム) ネットワークアダプタは、チェックサム値を計算し、その値をネットワークスタックに提供できるため、受信フラグメントの再アセンブリは柔軟に行われます。 フラグメントの再アセンブリの段階で、ネットワークスタックは、すべての値を結合することによって、断片化されていないデータグラムのチェックサム状態を求めることができます。 IP オプションがある場合は、チェックサムをオフロードしないことにより、処理が簡単化されました。 部分チェックサムオフロードの場合、一部のアダプタでは、開始オフセットを単純な IP パケットに十分な幅に制限します。 オプションがあるためにプロトコルヘッダーの長さがこの制限を超える場合、開始オフセットが折り返すため、計算が正しく行われません。 完全チェックサムオフロードの場合、該当のアダプタで、IPV4 ソースルーティングオプションを正しく処理できるものはありません。 送信のチェックサムオフロードが発生すると、ネットワークスタックは、該当のパケットを、ドライバがチェックサム計算をハードウェアにオフロードするのに必要な付属情報に関連付けます。 インバウンドの場合、ドライバは、ハードウェアで計算されるチェックサム値に関連付けられているパケットを完全に制御できます。 ドライバが DL CAPAB HCKSUM を通じてその機能を通知すると、ネットワークスタックは、IPv4 および IPv6 パケットの完全または部分チェックサム情報を受け取ります。 このプロセスは、断片化されていないペイロードと断片化されたペイロードの両方について発生します。 チェックサム検証は完全に再アセンブリされたデータグラムに対して発生するため、断片化されたパケットは、最初に、再アセンブリプロセスを経由する必要があります。 再アセンブリの中で、ネットワークスタックは、ハードウェアで計算された各フラグメントのチェックサム値を結合します。 6.4.1
集積体のキーは、1 ~ 65535 の整数です。 デバイスによっては、構成可能なデータリンクまたは集積体をサポートしません。 このようなデバイスで提供される固定のデータリンクは、 GLDv3 フレームワークでは、ユーザーは、集積体を構成する一方で、集積体の各種メンバーにわたるアウトバウンド負荷分散ポリシーを選択できます。 ポリシーでは、パケットの送信に使用される dev オブジェクトを指定します。 ポリシーは、1 つ以上のレイヤー指定子をカンマで区切ったリストで構成されます。 レイヤー指定子は、次のいずれかです。
たとえば、上位レイヤーのプロトコル情報を使用するには、次のポリシーを使用します。 -P L4 発信元および送信先 IP アドレスに加えて、発信元および送信先 MAC アドレスを使用するには、次のポリシーを使用します。 -P L2,L3
フレームワークは、 新しいデバイスがシステムに挿入されると、再構成ブートまたは DR の際に、そのデバイスに対してデフォルトの非 VLAN データリンクが作成されます。 すべてのオブジェクトの構成は、リブートを通じて持続されます。
将来的には、 7.0 パフォーマンスのチューニング
Solaris 10 スタックのチューニングは、使用されているハードウェアにかかわらず、優れた革新的なパフォーマンスを実現するように工夫されています。 その秘訣は、割り込みモードとポーリングモードの動的な切り替えや、負荷が非常に高い場合にポーリングモードに切り替えてスループットを高めたり適切な待ち時間を定めるなどの手法を使用することにあります。NIC によるパケット単位の割り込みを許可することで負荷が管理可能な場合、割り込みモードとポーリングモードの動的な切り替えにより、待ち時間が大きく改善されます。 デフォルト値も、ハードウェア構成に基づいて慎重に選択されています。 たとえば、Solaris 10 以前のリリースでは、チューニング可能な変数 これらの機能にもかかわらず、場合によっては、チューニング可能ないくつかの変数に手を加えて、極端な場合や特定のワークロードに対処する必要があります。 次のセクションでは、スタックの動作を制御するチューニング可能変数について説明します。 その影響を十分に理解することが重要です。十分に理解しないままに操作すると、システムが不安定になることがあります。 ほとんどのアプリケーションとワークロードでは、デフォルト値で最適な結果が得られることに留意してください。
set ip:ip_squeue_fanout=1
set ip:ip_squeue_bind=0
デフォルト値は 2 ですが、 set ip:tcp_squeue_wput=1 CPU の数がアクティブな NIC の数よりはるかに多く、プラットフォームのメモリー待ち時間が本質的に長いため、アプリケーションスレッドが squeue のドレインを行い、動きが取れなくなる可能性が高い場合は、この値を 1 に設定します。
ip:ip_squeue_wait=0
また、特に大量のメモリーを搭載したシステムでは、プロトコルレベルのチューニング ( 8.0 今後の展望Solaris ネットワークスタックは、引き続き、レイヤー間の垂直統合を基礎とすることで、局所性とパフォーマンスのさらなる改善が期待されます。 チップマルチスレッドおよびマルチコア CPU の出現に伴い、ローエンドシステムでも、並列実行パイプライン数が増加し続けることが期待されます。 現代の一般的な 2 CPU マシンはデュアルコアであり、実行パイプライン数は 4 で、多くの場合ハイパースレッドにも対応しています。 NIC も高度になり、MSI-X による複数の割り込み、細かい分類機能、複数の DMA チャネル、大規模セグメントオフロードのような各種ステートレスオフロードなどを提供します。 今後、TCP オフロードエンジン、Remote Direct Memory Access (RDMA)、iSCSI のサポートを含めて、このようなハードウェアの動向を活用していくことが期待されます。 現在取り組んでいるその他の特別な分野は、次のとおりです。
9.0 謝辞この記事の一部を寄稿してくれた Thirumalai Srinivasan、Adi Masputra、Nicolas Droux、および Eric Cheng に感謝の意を表します。 Solaris ネットワークコミュニティーのすべてのメンバーにも、その支援に対して感謝の意を表します。 ここで取り上げたすべてのテクニカルマニュアル内のコード (記事、FAQ、サンプルを含む) は、特にほかのライセンス供与がないかぎり、このライセンスのもとに提供されています。 |
BigAdmin SubscriptionsBigAdmin Areas
BigAdmin Sun Center
BigAdmin Topics |