Linux Netlink 基本使用方法


  1.什么是Netlink
  什么是Netlink?Netlink是linux提供的用於內核和用戶態進程之間的通信方式。但是注意雖然Netlink主要用於用戶空間和內核空間的通信,但是也能用於用戶空間的兩個進程通信。只是進程間通信有其他很多方式,一般不用Netlink。除非需要用到Netlink的廣播特性時。
  那么Netlink有什么優勢呢?一般來說用戶空間和內核空間的通信方式有三種:/proc、ioctl、Netlink。而前兩種都是單向的,但是Netlink可以實現雙工通信。
  Netlink協議基於BSDsocket和AF_NETLINK地址簇(addressfamily),使用32位的端口號尋址(以前稱作PID),每個Netlink協議(或稱作總線,man手冊中則稱之為netlinkfamily),通常與一個或一組內核服務/組件相關聯,如NETLINK_ROUTE用於獲取和設置路由與鏈路信息、NETLINK_KOBJECT_UEVENT用於內核向用戶空間的udev進程發送通知等。netlink具有以下特點:
  ①支持全雙工、異步通信(當然同步也支持)https://www.weixiu3721.com
  ②用戶空間可使用標准的BSDsocket接口(但netlink並沒有屏蔽掉協議包的構造與解析過程,推薦使用libnl等第三方庫)
  ③在內核空間使用專用的內核API接口
  ④支持多播(因此支持“總線”式通信,可實現消息訂閱)
  ⑤在內核端可用於進程上下文與中斷上下文
  如何學習Netlink?我覺得最好的方式就是將Netlink和UDPsocket對比學習。因為他們真的很對地方相似。AF_NETLINK和AF_INET對應,是一個協議族,而NETLINK_ROUTE、NETLINK_GENERIC這些是協議,對應於UDP。
  那么我們主要關注Netlink和UDPsocket之間的不同點,其中最重要的一點就是:使用UDPsocket發送數據包時,用戶無需構造UDP數據包的包頭,內核協議棧會根據原、目的地址(sockaddr_in)填充頭部信息。但是Netlink需要我們自己構造一個包頭(這個包頭有什么用,我們后面再說)。
  一般我們使用Netlink都要指定一個協議,我們可以使用內核為我們預留的NETLINK_GENERIC(定義在linux/netlink.h中),也可以使用我們自定義的協議,其實就是定義一個內核還沒有占用的數字。下面我們用NETLINK_TEST做為我們定義的協議寫一個例子(注意:自定義協議不一定非要添加到linux/netlink.h中,只要用戶態和內核態代碼都能找到該定義就行)。我們知道使用UDP發送報文有兩種方式:sendto和sendmsg,同樣Netlink也支持這兩種方式。下面先看使用sendmsg的方式。
  2.用戶態數據結構
  首先看一下幾個重要的數據結構的關系:
  2.1structmsghdr
  msghdr這個結構在socket變成中就會用到,並不算Netlink專有的,這里不在過多說明。只說明一下如何更好理解這個結構的功能。我們知道socket消息的發送和接收函數一般有這幾對:recv/send、readv/writev、recvfrom/sendto。當然還有recvmsg/sendmsg,前面三對函數各有各的特點功能,而recvmsg/sendmsg就是要囊括前面三對的所有功能,當然還有自己特殊的用途。msghdr的前兩個成員就是為了滿足recvfrom/sendto的功能,中間兩個成員msg_iov和msg_iovlen則是為了滿足readv/writev的功能,而最后的msg_flags則是為了滿足recv/send中flag的功能,剩下的msg_control和msg_controllen則是滿足recvmsg/sendmsg特有的功能。
  2.2Structsockaddr_ln
  Structsockaddr_ln為Netlink的地址,和我們通常socket編程中的sockaddr_in作用一樣,他們的結構對比如下。
  structsockaddr_nl{}的詳細定義和描述如下:
  struct sockaddr_nl
  {
  sa_family_t nl_family;/*該字段總是為AF_NETLINK*/
  unsigned short nl_pad;/*目前未用到,填充為0*/
  __u32 nl_pid;/*process pid*/
  __u32 nl_groups;/*multicast groups mask*/
  };
  (1)nl_pid:在Netlink規范里,PID全稱是Port-ID(32bits),其主要作用是用於唯一的標識一個基於netlink的socket通道。通常情況下nl_pid都設置為當前進程的進程號。前面我們也說過,Netlink不僅可以實現用戶-內核空間的通信還可使現實用戶空間兩個進程之間,或內核空間兩個進程之間的通信。該屬性為0時一般指內核。
  (2)nl_groups:如果用戶空間的進程希望加入某個多播組,則必須執行bind()系統調用。該字段指明了調用者希望加入的多播組號的掩碼(注意不是組號,后面我們會詳細講解這個字段)。如果該字段為0則表示調用者不希望加入任何多播組。對於每個隸屬於Netlink協議域的協議,最多可支持32個多播組(因為nl_groups的長度為32比特),每個多播組用一個比特來表示。
  2.3structnlmsghdr
  Netlink的報文由消息頭和消息體構成,structnlmsghdr即為消息頭。消息頭定義在文件里,由結構體nlmsghdr表示:
  struct nlmsghdrhttps://www.weixiu3721.com
  {
  __u32 nlmsg_len;/*Length of message including header*/
  __u16 nlmsg_type;/*Message content*/
  __u16 nlmsg_flags;/*AddiTIonal flags*/
  __u32 nlmsg_seq;/*Sequence number*/
  __u32 nlmsg_pid;/*Sending process PID*/
  };
  消息頭中各成員屬性的解釋及說明:
  (1)nlmsg_len:整個消息的長度,按字節計算。包括了Netlink消息頭本身。
  (2)nlmsg_type:消息的類型,即是數據還是控制消息。目前(內核版本2.6.21)Netlink僅支持四種類型的控制消息,如下:
  a)NLMSG_NOOP-空消息,什么也不做;
  b)NLMSG_ERROR-指明該消息中包含一個錯誤;
  c)NLMSG_DONE-如果內核通過Netlink隊列返回了多個消息,那么隊列的最后一條消息的類型為NLMSG_DONE,其余所有消息的nlmsg_flags屬性都被設置NLM_F_MULTI位有效。
  d)NLMSG_OVERRUN-暫時沒用到。
  (3)nlmsg_flags:附加在消息上的額外說明信息,如上面提到的NLM_F_MULTI。
  那消息體怎么設置呢?可以使用NLMSG_DATA,具體見后面例子。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM