搜尋
首頁系統教程Linux使用Netlink進行使用者空間和核心空間之間的通信

用户空间和内核空间通讯-Netlink 上

#2001年,ForCES IETF委員會正式對Netlink進行了標準化的工作。 Jamal Hadi Salim提議將Netlink定義成一種用於網路設備的路由引擎元件和其控制管理元件之間通訊的協定。不過他的建議最終沒有被採納,取而代之的是我們今天所看到的格局:Netlink被設計成一個新的協議域,domain。

Linux之父托瓦斯曾說過「Linux is evolution, not intelligent design」。什麼意思?就是說,Netlink也同樣遵循了Linux的某些設計理念,即沒有完整的規範文檔,亦沒有設計文檔。只有什麼?你懂得---「Read the f**king source code」。

當然,本文不是分析Netlink在Linux上的實現機制,而是就「什麼是Netlink」以及「如何用好Netlink」的話題和大家做個分享,只有在遇到問題時才需要去閱讀內核源碼弄清個所以然。

什麼是Netlink

關於Netlink的理解,需要掌握幾個關鍵點:

1、以資料封包為導向的無連線訊息子系統

2、基於通用的BSD Socket架構而實作

關於第一點使我們很容易聯想到UDP協議,能想到這一點就非常棒了。按著UDP協議來理解Netlink不是不無道理,只要你能觸類旁通,做到“活學”,善於總結歸納、聯想,最後實現知識遷移這就是學習的本質。 Netlink可以實現內核->用戶以及用戶->內核的雙向、異步的數據通信,同時它還支援兩個用戶進程之間、甚至兩個內核子系統之間的數據通信。本文中,對後兩者我們不予考慮,焦點集中在如何實現使用者核心之間的資料通訊。

看到第二點腦海中是不是瞬間閃現了下面這張圖片呢?如果是,表示你確實有慧根;當然,不是也沒關係,慧根可以慢慢長嘛,呵呵。

在後面實戰Netlink套接字程式設計時我們主要會用到socket(),bind(),sendmsg()

和recvmsg()等系統調用,當然還有socket提供的輪訓(polling)機制。

Netlink通訊類型

Netlink支援兩種類型的通訊方式:單播和多播。

單播:常用於一個使用者程序和一個核心子系統之間1:1的資料通訊。使用者空間發送命令到內核,然後從內核接受命令的返回結果。

多播:經常用於一個核心行程和多個使用者行程之間的1:N的資料通訊。核心作為會話的發起者,用戶空間的應用程式是接收者。為了實現這個功能,核心空間的程式會創建一個多播組,然後所有用戶空間的對該內核進程發送的消息感興趣的進程都加入到該組即可接收來自內核發送的消息了。如下:

用户空间和内核空间通讯-Netlink 上

#其中進程A和子系統1之間是單播通信,進程B、C和子系統2是多播通信。上圖也向我們說明了一個訊息。從使用者空間傳遞到核心的資料是不需要排隊的,即其操作是同步完成;而從核心空間向使用者空間傳遞資料時需要排隊,是異步的。了解了這一點在開發基於Netlink的應用模組時可以使我們少走很多彎路。假如,你向核心發送了一個訊息需要獲取核心中某些訊息,例如路由表,或其他訊息,如果路由表過於龐大,那麼核心在透過Netlink向你返回資料時,你可以好生琢磨一下如何接收這些數據的問題,畢竟你已經看到了那個輸出隊列了,不能視而不見啊。

Netlink的訊息格式

Netlink訊息由兩部分組成:訊息頭和有效資料載荷,且整個Netlink訊息是4位元組對齊,一般按主機位元組序列進行傳遞。訊息頭為固定的16位元組,訊息體長度可變:

用户空间和内核空间通讯-Netlink 上

#Netlink的訊息標頭

訊息頭定義在檔案裡,由結構體nlmsghdr表示:

點選(此處)折疊或開啟

  1. struct nlmsghdr
  2. {
  3.     __u32        nlmsg_len;    /* Length of message including header */
  4.     __u16        nlmsg_type;    /* Message content */
  5.     __u16        nlmsg_flags;    /* Additional flags */
  6.     __u32        nlmsg_seq;    /* Sequence number */
  7.     __u32        nlmsg_pid;    /* Sending process PID */
  8. };

訊息標頭中各成員屬性的解釋及說明:

nlmsg_len:整個訊息的長度,以位元組計算。包括了Netlink訊息頭本身。

nlmsg_type:訊息的類型,也就是資料還是控制訊息。目前(核心版本2.6.21)Netlink僅支援四種類型的控制訊息,如下:

NLMSG_NOOP-空訊息,什麼事都不做;

NLMSG_ERROR-指明該訊息中包含一個錯誤;

NLMSG_DONE-如果核心透過Netlink佇列傳回了多個訊息,那麼佇列的最後一則訊息的型別為NLMSG_DONE,其餘所有訊息的nlmsg_flags屬性都被設定NLM_F_MULTI位元有效。

NLMSG_OVERRUN-暫時沒用到。

nlmsg_flags:附加在訊息上的額外說明訊息,如上面提到的NLM_F_MULTI。摘錄如下:

大家只要知道nlmsg_flags有多種取值就可以,至於每種值的作用和意義,透過Google和原始碼一定可以找到答案,這裡就不展開了。上一張2.6.21核心中所有的取值情況:

用户空间和内核空间通讯-Netlink 上

#nlmsg_seq:訊息序號。因為Netlink是面向資料封包的,所以存在遺失資料的風險,但是Netlink提供如何確保訊息不遺失的機制,讓程式開發人員根據其實際需求而實現。訊息序號一般和NLM_F_ACK類型的訊息聯合使用,如果使用者的應用程式需要保證其發送的每個訊息都成功被核心收到的話,那麼它發送訊息時需要用戶程式自己設定序號,核心收到該訊息後來對提取其中的序號,然後在發送給用戶程式回應訊息裡設定相同的序號。有點類似TCP的回應和確認機制。

注意:當核心主動向用戶空間發送廣播訊息時,訊息中的該欄位總是為0。

nlmsg_pid:當使用者空間的程序和核心空間的某個子系統之間透過Netlink建立了資料交換的通道後,Netlink會為每個這樣的通道分配一個唯一的數位識別。其主要作用是將來自用戶空間的請求訊息和回應訊息進行關聯。說得直白一點,假如用戶空間存在多個用戶進程,內核空間同樣存在多個進程,Netlink必須提供一種機制用於確保每一對「用戶-內核」空間通信的進程之間的數據交互不會發生紊亂。

用户空间和内核空间通讯-Netlink 上

#即,進程A、B透過Netlink向子系統1取得資訊時,子系統1必須確保回送給進程A的回應資料不會傳送到進程B那裡。主要適用於使用者空間的程序從核心空間取得資料的場景。通常情況下,用戶空間的進程在向核心發送訊息時一般透過系統呼叫getpid()將當前進程的進程號賦給該變量,即用戶空間的進程希望得到內核的回應時才會這麼做。從核心主動發送到用戶空間的消息該字段都被設定為0。

Netlink的訊息體

Netlink的訊息體採用TLV(Type-Length-Value)格式:

用户空间和内核空间通讯-Netlink 上

#Netlink每個屬性都由檔案裡的struct nlattr{}來表示:

用户空间和内核空间通讯-Netlink 上

#Netlink提供的錯誤指示訊息

內容

當使用者空間的應用程式和核心空間的進程之間透過Netlink通訊時發生了錯誤,Netlink必須向使用者空間通報這種錯誤。 Netlink對錯誤訊息進行了單獨封裝,

點選(此處)折疊或開啟

  1. struct nlmsgerr
  2. {
  3.     int        error; //標準的錯誤碼,且定義於errno.h頭檔中。可以用perror()來解釋
  4.     struct nlmsghdr msg; //指明了哪一則訊息觸發了結構體中error這個錯誤值
  5. };
Netlink程式設計需要注意的問題

基於Netlink的使用者-核心通信,有兩種情況可能會導致丟包:

1、記憶體耗盡;

2、用戶空間接收程序的緩衝區溢位。導致緩衝區溢位的主要原因有可能是:使用者空間的進程運作太慢;或接收佇列太短。

如果Netlink無法將訊息正確傳遞到使用者空間的接收進程,那麼使用者空間的接收進程在呼叫recvmsg()系統呼叫時就會傳回一個記憶體不足(ENOBUFS)的錯誤,這一點需要注意。換句話說,緩衝區溢位的狀況是不會發送在從用戶->核心的sendmsg()系統呼叫裡,原因前面我們也說過了,請大家自己思考一下。

當然,如果使用的是阻塞型socket通信,也就不存在記憶體耗盡的隱患了,這又是為什麼呢?趕快去谷歌一下,查什麼是阻塞型socket吧。學而不思則罔,思而不學則殆嘛。

Netlink的位址結構體

在TCP部落格文章中我們提到在Internet程式設計過程中所用到的位址結構體和標準位址結構體,它們和Netlink位址結構體的關係如下:

struct sockaddr_nl{}的詳細定義與描述如下:

用户空间和内核空间通讯-Netlink 上

#點選(此處)折疊或開啟

  1. struct sockaddr_nl
  2. #{
  3.     sa_family_t    nl_family;    /*該欄位總是為AF_NETLINK    */
  4.     unsigned short    nl_pad;        /* 目前未使用,且填入0*/
  5.     __u32        nl_pid;        /* process pid    */

  1.     __u32        nl_groups;    /* multicast groups mask */
};

nl_pid:該屬性為發送或接收訊息的進程ID,前面我們也說過,Netlink不僅可以實現用戶-核心空間的通訊還可使現實用戶空間兩個進程之間,或核心空間兩個進程之間的通信。此屬性為0時一般適用於下列兩種情況: 第一,我們要發送的目的地是內核,也就是從用戶空間發送到內核空間時,我們建構的Netlink位址結構體中nl_pid通常情況下都置為0。這裡有一點需要跟大家交代一下,在Netlink規範裡,PID全名為Port-ID(32bits),其主要作用是用於唯一的標識一個基於netlink的socket通道。通常情況下nl_pid都會設定為目前進程的進程號。然而,對於一個行程的多個執行緒同時使用netlink socket的情況,nl_pid的設定一般採用如下這個樣子來實現: 點選(此處)折疊或開啟

pthread_self() 

第二,從核心發出的多播封包到用戶空間時,如果用戶空間的進程處在該多播群組中,那麼其位址結構體中nl_pid也設為0,同時也要結合下面介紹到的另一個屬性。

###nl_groups:如果使用者空間的程序希望加入某個多重播送群組,則必須執行bind()系統呼叫。此欄位指明了呼叫者希望加入的多重播放組號的######遮罩######(注意不是群組號,後面我們會詳細講解這個欄位)。如果該欄位為0則表示呼叫者不希望加入任何多播群組。對於每個隸屬於Netlink協議域的協議,最多可支援32個多播組(因為nl_groups的長度為32位元),每個多播群組都以一個位元來表示。 ### ###關於Netlink剩下的知識點,我們在後面的實戰環節有用到時再討論。 ### ###未完,待續…### ### ###

以上是使用Netlink進行使用者空間和核心空間之間的通信的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文轉載於:Linux就该这么学。如有侵權,請聯絡admin@php.cn刪除
Linux和Windows之間的用戶帳戶管理有什麼區別?Linux和Windows之間的用戶帳戶管理有什麼區別?May 02, 2025 am 12:02 AM

Linux和Windows在用戶賬戶管理上的主要區別在於權限模型和管理工具。 Linux使用基於Unix的權限模型和命令行工具(如useradd、usermod、userdel),而Windows採用自己的安全模型和圖形用戶界面(GUI)管理工具。

Linux的命令行環境如何使其比Windows更安全?Linux的命令行環境如何使其比Windows更安全?May 01, 2025 am 12:03 AM

Linux'scommandlinecanbemoresecurethanWindowsifmanagedcorrectly,butrequiresmoreuserknowledge.1)Linux'sopen-sourcenatureallowsforquicksecurityupdates.2)Misconfigurationcanleadtovulnerabilities.Windows'commandlineismorecontrolledbutlesscustomizable,with

如何在Linux中自動製作USB驅動器安裝如何在Linux中自動製作USB驅動器安裝Apr 30, 2025 am 10:04 AM

本指南說明瞭如何在Linux的啟動下自動安裝USB驅動器,從而節省了時間和精力。 步驟1:確定您的USB驅動器 使用LSBLK命令列出所有塊設備。 您的USB驅動器可能會標記為 /dev /sdb1, /dev /sdc1等

2025年,最佳Linux,Windows和Mac的最佳跨平台應用程序2025年,最佳Linux,Windows和Mac的最佳跨平台應用程序Apr 30, 2025 am 09:57 AM

跨平台應用程序已徹底改變了軟件開發,從而在Linux,Windows和MacOS等操作系統上實現了無縫功能。 這消除了根據您的設備切換應用程序的需求,提供一致的體驗

2025年AI和機器學習的最佳Linux工具2025年AI和機器學習的最佳Linux工具Apr 30, 2025 am 09:44 AM

人工智能(AI)正在迅速改變許多部門,從醫療保健和金融到藝術和音樂等創意領域。 Linux具有開源性,適應性和性能功能,已成為首要的Platfo

5最佳輕巧的Linux發行版,不帶GUI5最佳輕巧的Linux發行版,不帶GUIApr 30, 2025 am 09:38 AM

尋找沒有圖形用戶界面(GUI)的快速,最小和高效的Linux分佈? 輕巧,無GUI-Linux發行版非常適合較舊的硬件或服務器和嵌入式系統(例如服務器和嵌入式系統)。他們消耗較少的res

如何在Redhat發行中安裝葡萄酒10.0如何在Redhat發行中安裝葡萄酒10.0Apr 30, 2025 am 09:32 AM

Wine 10.0穩定版發布:在Linux上運行Windows應用更上一層樓 Wine,這款開源免費的應用程序,讓Linux用戶能夠在Unix/Linux類操作系統上運行Windows軟件和遊戲,迎來了10.0穩定版的發布!此版本已提供源代碼和二進制包下載,支持Linux、Windows和Mac等多種發行版。 這一版本凝聚了一年的辛勤工作和超過8600項改進,帶來了諸多令人興奮的提升。主要亮點包括: 增強對藍牙設備的支持。 提升對HID輸入設備的支持。 優化了32位和64位應用程序的運行性能。

如何在RHEL上安裝和配置SQL Server如何在RHEL上安裝和配置SQL ServerApr 30, 2025 am 09:27 AM

該教程通過在RHEL 8.x或9.x上安裝SQL Server 2022,通過SQLCMD命令行工具,數據庫創建和基本查詢連接。 先決條件 開始之前,請確保: 支持的RHEL版本(RHEL 8或9)。 Sudo

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

SecLists

SecLists

SecLists是最終安全測試人員的伙伴。它是一個包含各種類型清單的集合,這些清單在安全評估過程中經常使用,而且都在一個地方。 SecLists透過方便地提供安全測試人員可能需要的所有列表,幫助提高安全測試的效率和生產力。清單類型包括使用者名稱、密碼、URL、模糊測試有效載荷、敏感資料模式、Web shell等等。測試人員只需將此儲存庫拉到新的測試機上,他就可以存取所需的每種類型的清單。

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

Dreamweaver Mac版

Dreamweaver Mac版

視覺化網頁開發工具