ROUTE(4)

名称
route - カーネルパケット転送データベース

書式
#include <sys/types.h> #include <sys/time.h> #include <sys/socket.h> #include <net/if.h> #include <net/route.h> int socket(PF_ROUTE, SOCK_RAW, int family)

解説
UNIX はパケットルーティング装置を提供します。 カーネルはルーティング情報データベースを管理しています。 そして、ルーティング情報データベースは、パケットを転送する際に 適当なネットワークインタフェースを選択するのに使用されます。

ユーザプロセス (あるいは複数の共同プロセス) は、 特殊なソケットを通してメッセージを送ることによって このデータベースを管理します。 これは、初期のリリースで使われていた固定サイズの ioctl(2) での管理にとって代わったものです。 ルーティングテーブルの変更はスーパユーザによってのみ行なわれます。

オペレーティングシステムは、リダイレクトを受け取ったとか、 要求に対して適当な経路を設定することに失敗したというような 外部イベントに対する反応として、 自発的にルーティングメッセージを出すかもしれません。 このメッセージタイプの詳細は以下に記述されています。

ルーティングデータベースのエントリは 2 種類からなります。 1 つは特定のホスト向け、もう 1 つは (ビットマスクとマスク後に残る値によって指定される) 一般的なサブネットワーク内の全てのホスト向けです。 ワイルドカードやデフォルト経路の効果は、 すべてのビットが 0 のマスクを使用することによって 生じます。 それは階層的な経路になっているかもしれません。

システムが起動してネットワークインタフェースにアドレスが割り当てられる時、 各プロトコルファミリは、トラフィックに対して準備ができた時点で 各インタフェースにルーティングテーブルエントリをインストールします。 通常プロトコルは、各インタフェースを通して 宛先となるホストまたはネットワークへ “直接” 接続するものとして経路を指定します。 もし経路が直接であれば、 パケット内で指定されているのと同じホストへそれが送られるよう プロトコルファミリのトランスポート層が要求します。 そうでなければ、 ルーティングエントリにリストされたゲートウェイに 該当パケットを送るようにインタフェースが要求されます (即ち、パケットは転送されます)。

パケットがルーティングされる時、 カーネルは宛先に最も明確に一致する経路を見付けようと試みます。 (もし 2 つの異なるマスクがあって、マスクをかけた後の値が 一致しているペアがあるなら、 より明確に一致するというのはマスクの中のビットがより多く 立っている方です。 ホストへの経路は、宛先中のビットが最も多く 1 になっている マスクを持っているとみなされます)。 エントリが見つからなければ、宛先には到達不能であると宣言され、 以下で記述される経路制御ソケット上でメッセージ待ちをしている リスナがいれば routing-miss メッセージが生成されます。

ワイルドカードルーティングエントリは、宛先アドレスが 0 で マスクもすべて 0 で指定されます。 ワイルドカード経路は、システムが宛先に一致する経路を見つけるのに 失敗した時に使用されます。 ワイルドカード経路とルーティングリダイレクトとを 組み合わせて使用すると、ルーティングにかかるトラフィックを 合理的に軽減できる機構を提供できます。

上の書式で示されるソケットコールを使って経路制御メッセージを やりとりするとめのチャネルをオープンします。

family パラメータは、 すべてのアドレスファミリについての経路情報を提供する AF_UNSPEC をとることができます。あるいは、どのアドレスファミリを希望するか 指定することによって特定の アドレスファミリだけに限定することも出来ます。 1 つのシステムで 1 つ以上のルーティングソケットをオープンすることが出来ます。

メッセージは ヘッダとそれに続くいくつかの sockaddr (特に ISO の場合、可変長) によって構成され、 位置によって解釈され、 sockaddr の新しい length エントリによって区切られます。 例えば、4 つのアドレスをもったメッセージは ISO リダイレクトかもしれません。つまり 宛先、ネットマスク、ゲートウェイ、リダイレクトの作者です。 どのアドレスが表されているかの解釈はヘッダ内のビットマスクで 与えられます。 順序は、vector 内の最下位ビットから最上位ビットへの順になります。

カーネルに送られるメッセージはすべて返され、 メッセージ待ちをしているすべてのリスナにはそのコピーが 送られます。 カーネルはメッセージを送るプロセスのプロセス ID を提供します。 そして、メッセージを送るプロセスは、未解決のメッセージ同士を 区別するための 付加シーケンスフィールドを用いるかもしれません。 しかし、カーネルバッファが一杯であるとメッセージの返答は 失われるかもしれません。

カーネルは特定のメッセージを拒否し、 rtm_errno フィールドを埋めることによってそれを示します。 ルーティングコードは、 もしすでに存在するエントリを複写しようとすると EEXIST を、 存在しないエントリを削除しようとすると ESRCH を、 新しい経路を導入するために必要な資源が足りない場合は ENOBUFS を返します。 現在の実装では、すべてのルーティングプロセスはローカルで動作して いるので、ルーティング返答メッセージが失われたとしても rtm_errno の値は、通常の errno 機構から入手可能です。

プロセスは、 SOL_SOCKET レベルでの SO_USELOOPBACK オプションをオフにすることを示す setsockopt(2) コールを発行することで、自分自身のメッセージに対する返答を 読む負荷を回避することができます。 プロセスは更に shutdown(2) システムコールを行なうことによって ルーティングソケットからのすべてのメッセージを無視することができます。

もし経路が使用中に削除されると、 そのルーティングエントリにはダウンとマークされ、 経路表から除かれます。 しかしそれに関連づけられた資源は、経路への参照がすべて 解放されるまで返還されません。 ユーザプロセスは、 RTM_GET メッセージを使うか、 /dev/kmem デバイスを読むか、あるいは getkerninfo(2) システムコールを発行することによって 特定の宛先へのルーティングエントリに関する情報を取得することが できます。

メッセージは次のものを含んでいます:

    #define	RTM_ADD		0x1    /* 経路追加 */
    #define	RTM_DELETE	0x2    /* 経路削除 */
    #define	RTM_CHANGE	0x3    /* メトリックやフラグやゲートウェイを変更 */
    #define	RTM_GET		0x4    /* 情報報告 */
    #define	RTM_LOOSING	0x5    /* カーネルは partitioning を疑っている */
    #define	RTM_REDIRECT	0x6    /* 別の経路を使うように言っている */
    #define	RTM_MISS	0x7    /* アドレス照合に失敗した */
    #define	RTM_RESOLVE	0xb    /* 宛先を LL addr に解決する要求 */

1 つのメッセージヘッダは以下から成ります:

    struct rt_msghdr {
        u_short rmt_msglen;  /* 分からないメッセージをスキップするため */
        u_char  rtm_version; /* 将来のバイナリ互換性 */
        u_char  rtm_type;    /* メッセージタイプ */
        u_short rmt_index;   /* 関連のある ifp のインデックス */
        int     rtm_flags;   /* フラグ、incl kern & message, 例えば DONE */
        int     rtm_addrs;   /* msg 中の sockaddr を識別するビットマスク */
        pid_t   rmt_pid;     /* 送信者を識別する */
        int     rtm_seq;     /* 送信者に対して動作を識別する */
        int     rtm_errno;   /* 何故失敗したか */
        int     rtm_use;     /* rtentry から */
        u_long  rtm_inits;   /* どの値を初期化するか */
        struct  rt_metrics rtm_rmx;	/* メトリック自身 */
    };

ここで “struct rt_metrics” およびフラグビットは rtentry(9) で定義されています。

rms_locks と rms_inits のメトリック値の指定子は次の通りです:

    #define	RTV_SSTHRESH  0x1    /* _ssthresh の初期化あるいはロック */
    #define	RTV_RPIPE     0x2    /* _recvpipe の初期化あるいはロック */
    #define	RTV_SPIPE     0x4    /* _sendpipe の初期化あるいはロック */
    #define	RTV_HOPCOUNT  0x8    /* _hopcount の初期化あるいはロック */
    #define	RTV_RTT       0x10   /* _rtt の初期化あるいはロック */
    #define	RTV_RTTVAR    0x20   /* _rttvar の初期化あるいはロック */
    #define	RTV_MTU       0x40   /* _mtu の初期化あるいはロック */

メッセージ中でどのアドレスが渡されたかの指定子は次の通りです:

    #define RTA_DST       0x1    /* 宛先 sockaddr が渡された */
    #define RTA_GATEWAY   0x2    /* ゲートウェイ sockaddr が渡された */
    #define RTA_NETMASK   0x4    /* ネットマスク sockaddr が渡された */
    #define RTA_GENMASK   0x8    /* クローニング sockaddr が渡された */
    #define RTA_IFP       0x10   /* インタフェース名 sockaddr が渡された */
    #define RTA_IFA       0x20   /* インタフェースアドレス sockaddr が渡された */
    #define RTA_AUTHOR    0x40   /* リダイレクトの作者の sockaddr */

関連項目
route(8), rtentry(9)

歴史
PF_ROUTE プロトコルファミリは 4.3BSD reno で最初に現れました。