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
- カーネルコネクタ。
より詳しい情報はカーネルソースの
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_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
はビットマスクで、すべてのビットが
netlink
グループ番号を表す。
それぞれの netlink
ファミリーは 32
のマルチキャストグループのセットを持つ。
それぞれの netlink
ファミリーは 32
のマルチキャストグループの
セットを持つ。
bind(2)
がソケットに対して呼ばれると、
sockaddr_nl の
nl_groups
フィールドには listen
したいグループのビットマスクがセットされる。
デフォルトの値は 0
で、マルチキャストを一切受信しない。
sendmsg(2) や
connect(2)
によって、あるソケットからメッセージを
マルチキャストしたいときは、
nl_groups
に送信したいグループのビットマスク
をセットすればよい。
実効ユーザー ID が 0
か、
CAP_NET_ADMIN
権限を持つユーザーのみが
netlink
マルチキャストグループに
送信したり、これを
listen
したりすることができる。
マルチキャストグループ向けメッセージを受信した場合、これ対する応答は
送り主の PID
とマルチキャストグループとに送り返すべきである。
さらに、Linux
のカーネルサブシステムによっては、
他のユーザもメッセージの送受信ができる場合がある。
Linux 3.0 の時点では、
NETLINK_KOBJECT_UEVENT,
NETLINK_GENERIC,
NETLINK_ROUTE,
NETLINK_SELINUX
グループでは他のユーザがメッセージを受信することができる。
他のユーザがメッセージを送信できるグループは存在しない。
バージョン¶
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 = { (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)
/* 何らかのエラー処理を行う */
...
/* ペイロードの解析を続ける */
...
}
関連項目¶
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"
この文書について¶
この man ページは Linux
man-pages
プロジェクトのリリース
3.41 の一部
である。プロジェクトの説明とバグ報告に関する情報は
http://www.kernel.org/doc/man-pages/
に書かれている。