kazmax - Linux で自宅サーバー

netlink - 約束事その他の説明 - Linux コマンド集 一覧表

  1. 名前
  2. 書式
  3. 説明
  4. アドレスのフォーマット
  5. バグ
  6. 注意
  7. バージョン
  8. 関連項目

名前

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

書式

#include <asm/types.h>

#include <sys/socket.h>
#include <linux/netlink.h>

netlink_socket = socket(PF_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 アドレス・リンクパラメータ・近傍設定 (neighbour 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
カーネルコネクタ。 より詳しい情報はカーネルソースの 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;    /* 送信プロセスの PID */
};


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_seqnlmsg_pid はメッセージの追跡に使用される。 nlmsg_pid はメッセージの送信元を表す。 メッセージが netlink ソケットで送信されている場合、 nlmsg_pid とプロセスの PID は 1:1 の関係ではない点に注意すること。 より詳しい情報は、 「 アドレスのフォーマット 」のセクションを参照すること。
nlmsg_seqnlmsg_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 はビットマスクで、すべてのビットが netlink グループ番号を表す。 それぞれの netlink ファミリーは 32 のマルチキャストグループのセットを持つ。 それぞれの netlink ファミリーは 32 のマルチキャストグループの セットを持つ。   bind (2) がソケットに対して呼ばれると、 sockaddr_nlnl_groups フィールドには listen したいグループのビットマスクがセットされる。 デフォルトの値は 0 で、マルチキャストを一切受信しない。 sendmsg (2)や   connect (2) によって、あるソケットからメッセージをマルチキャストしたいときは、 nl_groups に送信したいグループのビットマスクをセットすればよい。 実効ユーザー ID が 0 か、 CAP_NET_ADMIN 権限を持つユーザーのみが netlink マルチキャストグループに 送信したり、これを listen したりすることができる。 マルチキャストグループ向けメッセージを受信した場合、これ対する応答は 送り主の PID とマルチキャストグループとに送り返すべきである。

以下の例では、 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)); snl.nl_family = AF_NETLINK; snl.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 = { (void *) nh, nh->nlmsg_len };
struct msghdr msg;


msg = { (void *)&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 = { (void *)&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) /* 何らかのエラー処理を行う */ ...
/* ペイロードの解析を続ける */ ... }

バグ

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

注意

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

バージョン

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 で登場した。

関連項目

  cmsg (3),   netlink (3),   capabilities (7),   rtnetlink (7) 

libnetlink に関する情報は ftp://ftp.inr.ac.ru/ip-routing/iproute2*
libnl に関する情報は http://people.suug.ch/~tgr/libnl/
RFC 3549 "Linux Netlink as an IP Services Protocol"