NETLINK(7)

名前
netlink - カーネルとユーザー空間の通信 (AF_NETLINK)

書式
#include <asm/types.h>
#include <sys/socket.h>
#include <linux/netlink.h>
netlink_socket = socket(AF_NETLINK, socket_type, netlink_family);

説明
netlink はカーネルモジュールとユーザー空間のプロセス間で 情報をやりとりするために用いられる。 netlink は、ユーザープロセスに対しては 標準的なソケットベースのインターフェースを、 カーネルモジュールにはカーネルの内部 API を提供する。 カーネル内部のインターフェースについてはこの man ページでは記述しない。 また、netlink キャラクタデバイスを用いた obsolete な netlink インターフェースもあるが、これもこの文書では解説しない。 これは過去互換性のためだけに用意されている。 netlink はデータグラム指向のサービスである。 socket_type には SOCK_RAW と SOCK_DGRAM の両方とも指定可能である。 しかし netlink プロトコルはデータグラムと raw ソケットの区別をしない。 netlink_family は、通信するカーネルモジュールや netlink グループの選択に用いる。 現在割り当てられている netlink ファミリーは以下の通り。

NETLINK_ROUTE
    ルーティングとリンクの更新を受信する。 (IPv4 と IPv6 両方の) ルーティングテーブル・ IP アドレス・リンクパラメータ・近傍設定 (neighbor setup)・ キューイングルール (queueing dicipline)・トラフィッククラス・ パケットのクラス分類の修正に用いることができるだろう (rtnetlink(7) を見よ)。

NETLINK_W1
    単線 (1-wire) のサブシステムからのメッセージ。

NETLINK_USERSOCK
    ユーザーモードソケットプロトコルのために予約されている。

NETLINK_FIREWALL
    IPv4 パケットを netfilter からユーザー空間へ転送する。 ip_queue カーネルモジュールで使用される。

NETLINK_INET_DIAG
    INET ソケットをモニタリングする。

NETLINK_NFLOG
    Netfilter/iptables ULOG.

NETLINK_XFRM
    IPsec.

NETLINK_SELINUX
    SELinux のイベント通知。

NETLINK_ISCSI
    Open-iSCSI.

NETLINK_AUDIT
    監査 (audit) を行う。

NETLINK_FIB_LOOKUP
    ユーザー空間から FIB ルックアップにアクセスする。

NETLINK_CONNECTOR
    カーネルコネクタ。より詳しい情報は Linux カーネルソースの Documentation/connector/* を参照すること。

NETLINK_NETFILTER
    netfilter サブシステム。

NETLINK_IP6_FW
    IPv6 パケットを netfilter からユーザー空間へ転送する。 ip6_queue カーネルモジュールで使用される。

NETLINK_DNRTMSG
    DECnet ルーティングメッセージ。

NETLINK_KOBJECT_UEVENT
    ユーザー空間へのカーネルメッセージ

NETLINK_GENERIC
    netlink を簡単に使用するための一般的な netlink ファミリー。

netlink メッセージはバイトストリームからなり、 一つ以上の nlmsghdr ヘッダと、それに対応するペイロード (payload) が含まれる。 バイトストリームには、標準の NLMSG_* マクロによってのみアクセスすべきである。 より詳しい情報は netlink(3) を見よ。 マルチパートメッセージ (一つ以上の nlmsghdr ヘッダと、それに対応するペイロードが 一つバイトストリームに含まれる) においては、 先頭のヘッダ・後続のヘッダには NLM_F_MULTI フラグがセットされる。ただし最後のヘッダだけは例外で、 NLMSG_DONE タイプとなる。 それぞれの nlmsghdr の後にはペイロードが続く。
struct nlmsghdr {
    __u32 nlmsg_len;    /* ヘッダを含むメッセージの長さ */
    __u16 nlmsg_type;   /* メッセージの内容のタイプ */
    __u16 nlmsg_flags;  /* 追加フラグ */
    __u32 nlmsg_seq;    /* シーケンス番号 */
    __u32 nlmsg_pid;    /* 送信者のポート ID */
};
nlmsg_type は標準のメッセージタイプのどれか一つである: NLMSG_NOOP メッセージは無視される。 NLMSG_ERROR メッセージはエラーを示し、ペイロードには nlmsgerr 構造体が入る。 NLMSG_DONE メッセージはマルチパートメッセージの終了を伝える。
struct nlmsgerr {
    int error;        /* 負または 0 の errno は応答を表す */
    struct nlmsghdr msg;  /* エラーを起こしたメッセージのヘッダ */
};
ある netlink ファミリーで指定できるメッセージタイプは、 通常もっと多い。これらに関しては適切な man ページを見てほしい。 たとえば NETLINK_ROUTE に関しては rtnetlink(7) に書いてある。
nlmsg_flags の標準フラグビット
NLM_F_REQUEST | 要求メッセージ全てでセットされなければならない。
NLM_F_MULTI | このメッセージはマルチパートメッセージの一部である。 マルチパートメッセージは NLMSG_DONE で終端する。
NLM_F_ACK | 成功した場合の応答を要求する。
NLM_F_ECHO | この要求をエコーする。

GET 要求における追加フラグビット
NLM_F_ROOT | 単一のエントリではなくテーブル全体を返す。
NLM_F_MATCH | メッセージの内容で渡された基準 (criteria) にマッチする全てのエントリを返す。 まだ実装されていない。
NLM_F_ATOMIC | テーブルのアトミックなスナップショットを返す。
NLM_F_DUMP | 便利なマクロ。(NLM_F_ROOT|NLM_F_MATCH) と同じ。

NLM_F_ATOMIC を使う場合は、 CAP_NET_ADMIN 権限を持つか実効ユーザー ID が 0 でなければならない点に注意すること。
NEW 要求における追加フラグビット
NLM_F_REPLACE | 現存のオブジェクトを置換する。
NLM_F_EXCL | すでにオブジェクトがあったら置換しない。
NLM_F_CREATE | まだオブジェクトがなければ作成する。
NLM_F_APPEND | オブジェクトリストの最後に追加する。

nlmsg_seq と nlmsg_pid はメッセージの追跡に使用される。 nlmsg_pid はメッセージの送信元を表す。 メッセージが netlink ソケットで送信されている場合、 nlmsg_pid とプロセスの PID は 1:1 の関係ではない点に注意すること。 より詳しい情報は、 「アドレスのフォーマット」 のセクションを参照すること。 nlmsg_seq と nlmsg_pid は netlink のコアには見えない (opaque)。 netlink は信頼性の高いプロトコルではない。 netlink はメッセージを行き先に届けるために最善を尽くすが、 メモリが足りなかったりエラーが起こったりすると メッセージを取りこぼすこともある。 信頼性の高い転送を行いたいときは、 送信者は受信者に応答を要求することもできる。 これには NLM_F_ACK フラグをセットする。 応答は NLMSG_ERROR パケットのエラーフィールドを 0 にしたものになる。 アプリケーションは自分自身のメッセージを受けたときには、 応答を生成しなければならない。 カーネルは失敗したパケットに対して、 NLMSG_ERROR メッセージを送ろうとする。 ユーザープロセスはこの慣習にも従う必要がある。 しかし、どのような場合でもカーネルからユーザーへの 信頼性の高い転送は不可能である。 ソケットバッファが満杯の場合、カーネルは netlink メッセージを送信できない。 メッセージは取りこぼされて、カーネルとユーザー空間プロセスは、 カーネルの状態についての同じビューを持つことができなくなる。 これが起こったこと (recvmsg(2) によって ENOBUFS エラーが返される) を検知して再び同期させるのは、 アプリケーションの責任である。

  アドレスのフォーマット
sockaddr_nl 構造体はユーザー空間やカーネル空間で netlink クライアントを記述する。 sockaddr_nl はユニキャスト (単一の接続先にだけ送られる) にもできるし、 netlink マルチキャストグループ (nl_groups が 0 でない場合) にも送ることができる。
struct sockaddr_nl {
    sa_family_t     nl_family;  /* AF_NETLINK */
    unsigned short  nl_pad;     /* 0 である */
    pid_t           nl_pid;     /* ポート ID */
    __u32           nl_groups;  /* マルチキャストグループマスク */
};
nl_pid は netlink ソケットのユニキャストアドレスである。 行き先がカーネルの場合は、常に 0 である。 ユーザー空間プロセスの場合、通常は nl_pid は行き先のソケットを所有しているプロセスの PID である。 ただし、 nl_pid はプロセスではなく netlink ソケットを同定する。 プロセスが複数の netlink ソケットを所有する場合、 nl_pid は最大でも一つのソケットのプロセス ID としか等しくならない。 nl_pid を netlink ソケットに割り当てる方法は 2 つある。 アプリケーションが bind(2) を呼ぶ前に nl_pid を設定する場合、 nl_pid が一意であることを確認するのはアプリケーションの責任となる。 アプリケーションが nl_pid を 0 に設定した場合、カーネルがこの値を割り当てる。 カーネルはプロセスが最初にオープンした netlink ソケットに対してプロセス ID を割り当て、 それ以降にプロセスが作成した全ての netlink ソケットにも一意な nl_pid を割り当てる。 nl_groups is a bit mask with every bit representing a netlink group number. Each netlink family has a set of 32 multicast groups. When bind(2) is called on the socket, the nl_groups field in the sockaddr_nl should be set to a bit mask of the groups which it wishes to listen to. The default value for this field is zero which means that no multicasts will be received. A socket may multicast messages to any of the multicast groups by setting nl_groups to a bit mask of the groups it wishes to send to when it calls sendmsg(2) or does a connect(2). Only processes with an effective UID of 0 or the CAP_NET_ADMIN capability may send or listen to a netlink multicast group. Since Linux 2.6.13, messages can't be broadcast to multiple groups. Any replies to a message received for a multicast group should be sent back to the sending PID and the multicast group. Some Linux kernel subsystems may additionally allow other users to send and/or receive messages. As at Linux 3.0, the NETLINK_KOBJECT_UEVENT, NETLINK_GENERIC, NETLINK_ROUTE, and NETLINK_SELINUX groups allow other users to receive messages. No groups allow other users to send messages.

バージョン
netlink へのソケットインターフェースは Linux 2.2 の新機能である。 Linux 2.0 は、もっと原始的なデバイスベースの netlink インターフェースを サポートしていた (これも互換性のために今でも使用できる)。 古いインターフェースに関してはここでは記述しない。 NETLINK_SELINUX は Linux 2.6.4 で登場した。 NETLINK_AUDIT は Linux 2.6.6 で登場した。 NETLINK_KOBJECT_UEVENT は Linux 2.6.10 で登場した。 NETLINK_W1, NETLINK_FIB_LOOKUP は Linux 2.6.13 で登場した。 NETLINK_INET_DIAG, NETLINK_CONNECTOR, NETLINK_NETFILTER は Linux 2.6.14 で登場した。 NETLINK_GENERIC, NETLINK_ISCSI は Linux 2.6.15 で登場した。

注意
低レベルのカーネルインターフェースより、 libnetlink または libnl を通して netlink を利用するほうが良いことが多い。

バグ
この man ページは完成していない。

例
以下の例では、 RTMGRP_LINK (ネットワークインターフェースの create/delete/up/down イベント) と RTMGRP_IPV4_IFADDR (IPv4 アドレスの add/delete イベント) マルチキャストグループを listen する NETLINK_ROUTE netlink を作成している。
struct sockaddr_nl sa;
memset(&sa, 0, sizeof(sa));
sa.nl_family = AF_NETLINK;
sa.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR;
fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
bind(fd, (struct sockaddr *) &sa, sizeof(sa));
次の例では、netlink メッセージをカーネル (pid 0) に送る方法を示している。 応答を追跡する際の信頼性を高めるために、アプリケーションが メッセージのシーケンス番号を正しく処理しなければならない点に注意すること。
struct nlmsghdr *nh;    /* 送信する nlmsghdr とペイロード */
struct sockaddr_nl sa;
struct iovec iov = { nh, nh->nlmsg_len };
struct msghdr msg;
msg = { &sa, sizeof(sa), &iov, 1, NULL, 0, 0 };
memset(&sa, 0, sizeof(sa));
sa.nl_family = AF_NETLINK;
nh->nlmsg_pid = 0;
nh->nlmsg_seq = ++sequence_number;
/* NLM_F_ACK を設定することで、カーネルに応答を要求する */
nh->nlmsg_flags |= NLM_F_ACK;
sendmsg(fd, &msg, 0);
最後は、netlink メッセージの読み込みの例である。
int len;
char buf[4096];
struct iovec iov = { buf, sizeof(buf) };
struct sockaddr_nl sa;
struct msghdr msg;
struct nlmsghdr *nh;
msg = { &sa, sizeof(sa), &iov, 1, NULL, 0, 0 };
len = recvmsg(fd, &msg, 0);
for (nh = (struct nlmsghdr *) buf; NLMSG_OK (nh, len);
     nh = NLMSG_NEXT (nh, len)) {
    /* マルチパートメッセージの終わり */
    if (nh->nlmsg_type == NLMSG_DONE)
        return;
    if (nh->nlmsg_type == NLMSG_ERROR)
        /* 何らかのエラー処理を行う */
    ...
    /* ペイロードの解析を続ける */
    ...
}

関連項目
cmsg(3), netlink(3), capabilities(7), rtnetlink(7) information about libnetlink (ftp://ftp.inr.ac.ru/ip-routing/iproute2*) information about libnl (http://people.suug.ch/~tgr/libnl/) RFC 3549 "Linux Netlink as an IP Services Protocol"

この文書について
この man ページは Linux man-pages プロジェクトのリリース 3.51 の一部 である。プロジェクトの説明とバグ報告に関する情報は http://www.kernel.org/doc/man-pages/ に書かれている。