NETLINK - Linux手册页

时间:2019-08-20 18:02:00  来源:igfitidea点击:

Linux程序员手册 第7部分
更新日期: 2020-06-09

名称

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用于在内核进程和用户空间进程之间传输信息。它由一个用于用户空间进程的基于套接字的标准接口和一个用于内核模块的内部内核API组成。内部内核接口未在本手册页中介绍。通过netlink字符设备还有一个过时的netlink接口。该接口在此处未记录,仅出于向后兼容的目的而提供。

Netlink是面向数据报的服务。 SOCK_RAW和SOCK_DGRAM都是socket_type的有效值。但是,netlink协议不能区分数据报和原始套接字。

netlink_family选择要与之通信的内核模块或netlink组。当前分配的netlink系列是:

NETLINK_ROUTE
接收路由和链接更新,并可用于修改路由表(IPv4和IPv6),IP地址,链接参数,邻居设置,排队规则,流量类别和数据包分类器(请参阅rtnetlink(7))。
NETLINK_W1(Linux 2.6.13 to 2.16.17)
来自1-wire子系统的消息。
NETLINK_USERSOCK
保留用于用户模式套接字协议。
NETLINK_FIREWALL(up to and including Linux 3.4)
将IPv4数据包从netfilter传输到用户空间。由ip_queue内核模块使用。经过长时间的声明(支持更高级的nfnetlink_queue功能),在Linux 3.5中删除了NETLINK_FIREWALL。
NETLINK_SOCK_DIAG(since Linux 3.3)
从内核查询有关各种协议系列的套接字的信息(请参阅sock_diag(7))。
NETLINK_INET_DIAG(since Linux 2.6.14)
NETLINK_SOCK_DIAG的过时同义词。
NETLINK_NFLOG(up to and including Linux 3.16)
Netfilter / iptables ULOG。
NETLINK_XFRM
IPsec。
NETLINK_SELINUX(since Linux 2.6.4)
SELinux事件通知。
NETLINK_ISCSI(since Linux 2.6.15)
开放式iSCSI。
NETLINK_AUDIT(since Linux 2.6.6)
审核。
NETLINK_FIB_LOOKUP(since Linux 2.6.13)
从用户空间访问FIB查找。
NETLINK_CONNECTOR(since Linux 2.6.14)
内核连接器。有关更多信息,请参阅Linux内核源代码树中的Documentation / driver-api / connector.rst(或内核5.2及更低版本中的/Documentation/connector/connector.*)。
NETLINK_NETFILTER(since Linux 2.6.14)
Netfilter子系统。
NETLINK_SCSITRANSPORT(since Linux 2.6.19)
SCSI传输。
NETLINK_RDMA(since Linux 3.0)
Infiniband RDMA。
NETLINK_IP6_FW(up to and including Linux 3.4)
将IPv6数据包从netfilter传输到用户空间。由ip6_queue内核模块使用。
NETLINK_DNRTMSG
DECnet路由消息。
NETLINK_KOBJECT_UEVENT(since Linux 2.6.10)
向用户空间发送内核消息。
NETLINK_GENERIC(since Linux 2.6.15)
通用netlink系列,简化了netlink的使用。
NETLINK_CRYPTO(since Linux 3.2)
Netlink接口,用于请求有关向内核加密API注册的密码的信息,以及允许配置内核加密API。

Netlink消息由具有一个或多个nlmsghdr标头和相关负载的字节流组成。只能使用标准NLMSG_ *宏访问字节流。有关更多信息,请参见netlink(3)。

在多部分消息(一个字节流中具有相关负载的多个nlmsghdr头)中,第一个和所有后续头均设置了NLM_F_MULTI标志,但最后一个头的类型为NLMSG_DONE。

在每个nlmsghdr之后,有效负载随之而来。

struct nlmsghdr {
    __u32 nlmsg_len;    /* Length of message including header */
    __u16 nlmsg_type;   /* Type of message content */
    __u16 nlmsg_flags;  /* Additional flags */
    __u32 nlmsg_seq;    /* Sequence number */
    __u32 nlmsg_pid;    /* Sender port ID */
};

nlmsg_type可以是标准消息类型之一:NLMSG_NOOP消息将被忽略,NLMSG_ERROR消息表示错误,并且有效载荷包含nlmsgerr结构,NLMSG_DONE消息终止多部分消息。

struct nlmsgerr {
    int error;        /* Negative errno or 0 for acknowledgements */
    struct nlmsghdr msg;  /* Message header that caused the error */
};

一个netlink系列通常指定更多消息类型,请参见相应的手册页,例如NETLINK_ROUTE的rtnetlink(7)。

单元格不一致单元格不一致

请注意,NLM_F_ATOMIC需要CAP_NET_ADMIN功能或有效UID为0。

单元格不一致

nlmsg_seq和nlmsg_pid用于跟踪消息。 nlmsg_pid显示消息的来源。请注意,如果消息来自netlink套接字,则nlmsg_pid与进程的PID之间没有1:1的关系。有关更多信息,请参见"地址格式"部分。

对于netlink核心,nlmsg_seq和nlmsg_pid都是不透明的。

Netlink不是可靠的协议。它会尽力将消息传递到其目的地,但是当内存不足或发生其他错误时可能会丢弃消息。为了可靠传输,发送者可以通过设置NLM_F_ACK标志来向接收者请求确认。确认是一个NLMSG_ERROR数据包,错误字段设置为0。应用程序必须为接收到的消息本身生成确认。内核尝试为每个失败的数据包发送NLMSG_ERROR消息。用户进程也应遵循此约定。

但是,无论如何,从内核到用户的可靠传输都是不可能的。如果套接字缓冲区已满,内核将无法发送netlink消息:该消息将被丢弃,内核和用户空间进程将不再具有相同的内核状态视图。由应用程序来确定何时发生这种情况(通过recvmsg(2)返回的ENOBUFS错误)并重新同步。

Address formats

sockaddr_nl结构描述了用户空间或内核中的netlink客户端。 sockaddr_nl可以是单播(仅发送到一个对等方),也可以发送到netlink组播组(nl_groups不等于0)。

struct sockaddr_nl {
    sa_family_t     nl_family;  /* AF_NETLINK */
    unsigned short  nl_pad;     /* Zero */
    pid_t           nl_pid;     /* Port ID */
    __u32           nl_groups;  /* Multicast groups mask */
};

nl_pid是netlink套接字的单播地址。如果目标位于内核中,则始终为0。对于用户空间进程,nl_pid通常是拥有目标套接字的进程的PID。但是,nl_pid标识一个netlink套接字,而不是一个进程。如果一个进程拥有多个netlink套接字,则nl_pid最多只能等于一个套接字的进程ID。有两种方法将nl_pid分配给netlink套接字。如果应用程序在调用bind(2)之前设置了nl_pid,则由应用程序确定nl_pid是唯一的。如果应用程序将其设置为0,则内核将负责分配它。内核将进程ID分配给该进程打开的第一个netlink套接字,并为该进程随后创建的每个netlink套接字分配一个唯一的nl_pid。

nl_groups是一个位掩码,每个位代表一个网络链接组号。每个netlink系列都有一组32个多播组。在套接字上调用bind(2)时,应将sockaddr_nl中的nl_groups字段设置为希望监听的组的位掩码。该字段的默认值为零,这意味着将不会接收到任何多播。通过在调用sendmsg(2)或进行connect(2)时,将nl_groups设置为希望发送到的组的位掩码,套接字可以将消息组播到任何多播组。只有有效UID为0或CAP_NET_ADMIN功能的进程才能发送或侦听Netlink多播组。从Linux 2.6.13开始,无法将消息广播到多个组。对多播组收到的消息的任何答复都应发送回发送PID和多播组。一些Linux内核子系统可能另外允许其他用户发送和/或接收消息。从Linux 3.0开始,NETLINK_KOBJECT_UEVENTNETLINK_GENERIC,NETLINK_ROUTE和NETLINK_SELINUX组允许其他用户接收消息。没有群组允许其他用户发送消息。

Socket options

要设置或获取netlink套接字选项,请调用getsockopt(2)进行读取,或调用setsockopt(2)来编写选项级别参数设置为SOL_NETLINK的选项。除非另有说明,否则optval是指向int的指针。

NETLINK_PKTINFO(since Linux 2.6.14)
为接收到的数据包启用nl_pktinfo控制消息以获取扩展的目标组号。
NETLINK_ADD_MEMBERSHIP, NETLINK_DROP_MEMBERSHIP(since Linux 2.6.14)
加入/离开optval指定的组。
NETLINK_LIST_MEMBERSHIPS(since Linux 4.2)
检索套接字所属的所有组。 optval是指向__u32的指针,而optlen是数组的大小。该数组将填充套接字的完整成员资格集,并且所需的数组大小以optlen返回。
NETLINK_BROADCAST_ERROR(since Linux 2.6.30)
如果未设置,netlink_broadcast()仅报告ESRCH错误,而静默忽略ENOBUFS错误。
NETLINK_NO_ENOBUFS(since Linux 2.6.30)
单播和广播侦听器可以使用此标志,以避免收到ENOBUFS错误。
NETLINK_LISTEN_ALL_NSID(since Linux 4.2)
设置后,此套接字将接收来自所有网络名称空间的netlink通知,这些网络名称空间已将nsid分配给已打开套接字的网络名称空间。 nsid通过辅助数据发送到用户空间。
NETLINK_CAP_ACK(since Linux 4.2)
内核可能无法将确认消息的必要空间分配回用户空间。此选项将修剪原始网络链接消息的有效负载。网络链接消息头仍然包括在内,因此用户可以从序列号中猜测哪个消息触发了确认。

版本

netlink的套接字接口首先出现在Linux 2.2中。

Linux 2.0支持更原始的基于设备的netlink接口(仍可作为兼容性选项使用)。这个过时的界面在这里不再描述。

备注

通过libnetlink或libnl使用netlink通常比通过低级内核接口使用netlink更好。

BUGS

本手册页面不完整。

示例

下面的示例创建一个NETLINK_ROUTE netlink套接字,该套接字将侦听RTMGRP_LINK(网络接口创建/删除/打开/关闭事件)和RTMGRP_IPV4_IFADDR(IPv4地址添加/删除事件)多播组。

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));

下一个示例演示如何向内核发送网络链接消息(pid 0)。请注意,应用程序必须注意消息序列号,以便可靠地跟踪确认。

struct nlmsghdr *nh;    /* The nlmsghdr with payload to send */
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;
/* Request an ack from kernel by setting NLM_F_ACK */
nh->nlmsg_flags |= NLM_F_ACK;

sendmsg(fd, &msg, 0);

最后一个示例是有关读取netlink消息的。

int len;
/* 8192 to avoid message truncation on platforms with
   page size > 4096 */
struct nlmsghdr buf[8192/sizeof(struct nlmsghdr)];
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)) {
    /* The end of multipart message */
    if (nh->nlmsg_type == NLMSG_DONE)
        return;

    if (nh->nlmsg_type == NLMSG_ERROR)
        /* Do some error handling */
    ...

    /* Continue with parsing payload */
    ...
}

另外参见

cmsg(3),netlink(3),功能(7),rtnetlink(7),sock_diag(7)

有关libnetlink的信息

有关libnl的信息

RFC 3549" Linux Netlink作为IP服务协议"

出版信息

这个页面是Linux手册页项目5.08版的一部分。有关项目的说明、有关报告错误的信息以及此页面的最新版本,请访问https://www.kernel.org/doc/man-pages/