NETLINK

NETLINK(7)Linux程序员手册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用于在内核进程和用户空间进程之间传输信息。它由一个用于用户空间进程的基于套接字的标准接口和一个用于内核模块的内部内核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至2.16.17)
          来自1-wire子系统的消息。

   NETLINK_USERSOCK
          保留用于用户模式套接字协议。

   NETLINK_FIREWALL(Linux 3.4以下)
          将IPv4数据包从netfilter传输到用户空间。由ip_queue内核模块使用。经过长时间的声明(支持更高级的nfnetlink_queue功能),在Linux 3.5中删除了NETLINK_FIREWALL。

   NETLINK_INET_DIAG(从Linux 2.6.14开始)
          从内核查询有关各种协议系列的套接字的信息(请参阅sock_diag(7))。

   NETLINK_SOCK_DIAG(从Linux 3.3开始)
          NETLINK_INET_DIAG的同义词。

   NETLINK_NFLOG(直到并包括Linux 3.16)
          Netfilter / iptables ULOG。

   NETLINK_XFRM
          IPsec。

   NETLINK_SELINUX(从Linux 2.6.4开始)
          SELinux事件通知。

   NETLINK_ISCSI(从Linux 2.6.15开始)
          开放式iSCSI。

   NETLINK_AUDIT(从Linux 2.6.6开始)
          审核。

   NETLINK_FIB_LOOKUP(从Linux 2.6.13开始)
          从用户空间访问FIB查找。

   NETLINK_CONNECTOR(从Linux 2.6.14开始)
          内核连接器。有关更多信息,请参见Linux内核源代码树中的Documentation / connector / *。

   NETLINK_NETFILTER(从Linux 2.6.14开始)
          Netfilter子系统。

   NETLINK_SCSITRANSPORT(从Linux 2.6.19开始)
          SCSI传输。

   NETLINK_RDMA(从Linux 3.0开始)
          Infiniband RDMA。

   NETLINK_IP6_FW(不超过Linux 3.4)
          将IPv6数据包从netfilter传输到用户空间。由ip6_queue内核模块使用。

   NETLINK_DNRTMSG
          DECnet路由消息。

   NETLINK_KOBJECT_UEVENT(从Linux 2.6.10开始)
          向用户空间发送内核消息。

   NETLINK_GENERIC(从Linux 2.6.15开始)
          通用netlink系列,简化了netlink的使用。

   NETLINK_CRYPTO(从Linux 3.2开始)
          Netlink接口,用于请求有关向内核加密API注册的密码的信息,以及允许配置内核加密API。

Netlink消息由具有一个或多个nlmsghdr标头和相关负载的字节流组成。只能使用标准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错误;/ *负errno或0表示确认* /
           struct nlmsghdr msg; / *导致错误的消息头* /
       };

   一个netlink系列通常指定更多消息类型,请参见相应的手册页,例如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返回所有与邮件内容中传递的条件匹配的条目。尚未实施。
   NLM_F_ATOMIC返回表的原子快照。
   NLM_F_DUMP便利宏;等效于(NLM_F_ROOT | NLM_F_MATCH)。

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

   新请求的附加标志位
   ────────────────────────────────────────────────── ──────────
   NLM_F_REPLACE替换现有的匹配对象。
   NLM_F_EXCL如果对象已经存在,请不要替换。
   NLM_F_CREATE创建对象(如果尚不存在)。
   NLM_F_APPEND添加到对象列表的末尾。

   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错误)并重新同步。

地址格式
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_UEVENT,NETLINK_GENERIC,NETLINK_ROUTE和NETLINK_SELINUX组允许其他用户接收消息。没有群组允许其他用户发送消息。

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

   NETLINK_PKTINFO(从Linux 2.6.14开始)
          为接收到的数据包启用nl_pktinfo控制消息以获取扩展的目标组号。

   NETLINK_ADD_MEMBERSHIP,NETLINK_DROP_MEMBERSHIP(从Linux 2.6.14开始)
          加入/离开optval指定的组。

   NETLINK_LIST_MEMBERSHIPS(从Linux 4.2开始)
          检索套接字所属的所有组。optval是指向__u32的指针,而optlen是数组的大小。该数组填充有套接字的完整成员资格集,并且所需的数组大小以optlen返回。

   NETLINK_BROADCAST_ERROR(自Linux 2.6.30起)
          未设置时,netlink_broadcast()仅报告ESRCH错误,并静默忽略NOBUFS错误。

   NETLINK_NO_ENOBUFS(从Linux 2.6.30开始)
          单播和广播侦听器可以使用此标志,以避免收到ENOBUFS错误。

   NETLINK_LISTEN_ALL_NSID(从Linux 4.2开始)
          设置后,此套接字将从所有网络名称空间收到netlink通知,这些网络名称空间已将nsid分配给已打开套接字的网络名称空间。nsid通过辅助数据发送到用户空间。

   NETLINK_CAP_ACK(从Linux 4.2开始)
          内核可能无法将确认消息的必要空间分配回用户空间。此选项将修剪原始网络链接消息的有效负载。网络链接消息头仍然包括在内,因此用户可以从序列号中猜测哪个消息触发了确认。

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

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

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

BUG
本手册页面不完整。

example
下面的示例创建一个NETLINK_ROUTE网络链接套接字,该套接字将侦听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; / *具有有效负载的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从内核请求ack * /
       nh-> nlmsg_flags | = NLM_F_ACK;

       sendmsg(fd, &msg, 0);

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

       int len;
       char buf [8192]; / * 8192避免消息被页面大小> 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), sock_diag(7)

   有关libnetlink的信息⟨ftp://ftp.inr.ac.ru/ip-routing/iproute2*⟩

   有关libnl的信息⟨http://www.infradead.org/~tgr/libnl/⟩

   RFC 3549“ Linux Netlink作为IP服务协议”//RFC 3549 "Linux Netlink as an IP Services Protocol"

COLOPHON
该页面是Linux手册页项目4.16版的一部分。可以在https://www.kernel.org/doc/man-pages/上找到该项目的描述,有关报告错误的信息以及此页面的最新版本。

Linux 2017年9月15日NETLINK(7)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值