天天看點

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)

繼續閱讀