Logo

Linux 核心

6.16.0-rc4

快速搜尋

目錄

  • 開發流程
  • 提交補丁
  • 行為準則
  • 維護者手冊
  • 所有開發流程文件
  • 核心 API
  • 驅動 API
  • 子系統
  • 鎖
  • 許可規則
  • 編寫文件
  • 開發工具
  • 測試指南
  • Hacking 指南
  • 追蹤
  • 故障注入
  • 即時補丁
  • Rust
  • 管理
  • 構建系統
  • 報告問題
  • 使用者空間工具
  • 使用者空間 API
    • 系統呼叫
    • 安全相關介面
    • 裝置和 I/O
    • 其他
      • Linux 特定的 ELF 特性
      • Netlink 手冊
      • 平臺 Profile 選擇(例如 /sys/firmware/acpi/platform_profile)
      • VDUSE - “使用者空間中的 vDPA 裝置”
      • futex2
      • Perf 環形緩衝區
      • NT 同步原語驅動程式
  • 韌體
  • 韌體和裝置樹
  • CPU 架構
  • 未排序的文件
  • 翻譯

本頁

  • 顯示原始碼

Netlink 簡介¶

Netlink 通常被描述為 ioctl() 的替代品。它旨在用一種允許輕鬆新增或擴充套件引數的格式,來替代提供給 ioctl() 的固定格式 C 結構。

為了實現這一點,Netlink 使用一個最小的固定格式元資料頭,後跟多個 TLV(型別、長度、值)格式的屬性。

不幸的是,該協議多年來一直在發展,以一種有機的、無文件的方式發展,這使得很難連貫地解釋它。為了使其最具實用意義,本文件首先描述 Netlink 目前的使用方式,並在後面的章節中深入探討更多“歷史”用途。

開啟套接字¶

Netlink 通訊透過套接字進行,首先需要開啟一個套接字

fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);

套接字的使用允許以一種自然的方式在兩個方向(往返於核心)交換資訊。當應用程式 send() 請求時,操作仍然是同步執行的,但需要一個單獨的 recv() 系統呼叫來讀取回復。

因此,一個非常簡化的 Netlink“呼叫”流程看起來像

fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);

/* format the request */
send(fd, &request, sizeof(request));
n = recv(fd, &response, RSP_BUFFER_SIZE);
/* interpret the response */

Netlink 還為“轉儲”提供了自然支援,即向用戶空間傳遞某種型別的所有物件(例如,轉儲所有網路介面)。

fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);

/* format the dump request */
send(fd, &request, sizeof(request));
while (1) {
  n = recv(fd, &buffer, RSP_BUFFER_SIZE);
  /* one recv() call can read multiple messages, hence the loop below */
  for (nl_msg in buffer) {
    if (nl_msg.nlmsg_type == NLMSG_DONE)
      goto dump_finished;
    /* process the object */
  }
}
dump_finished:

socket() 呼叫的前兩個引數幾乎不需要解釋 - 它正在開啟一個 Netlink 套接字,所有標頭都由使用者提供(因此是 NETLINK、RAW)。最後一個引數是 Netlink 中的協議。此欄位用於標識套接字將與之通訊的子系統。

經典 Netlink 與通用 Netlink¶

Netlink 的初始實現依賴於子系統的靜態 ID 分配,並且幾乎沒有提供支援基礎設施。讓我們將這些協議統稱為 **經典 Netlink**。它們的列表在 `include/uapi/linux/netlink.h` 檔案的頂部定義,它們包括 - 通用網路 (NETLINK_ROUTE)、iSCSI (NETLINK_ISCSI) 和審計 (NETLINK_AUDIT) 等。

**通用 Netlink**(於 2005 年推出)允許動態註冊子系統(和子系統 ID 分配)、內省,並簡化了介面的核心側實現。

以下部分描述瞭如何使用通用 Netlink,因為使用通用 Netlink 的子系統數量比舊協議多一個數量級。也沒有計劃向核心新增更多經典 Netlink 協議。本文件稍後提供了有關與 Linux 核心的核心網路部分(或使用經典 Netlink 的其他 20 個子系統)進行通訊的方式與通用 Netlink 的基本資訊。

通用 Netlink¶

除了 Netlink 固定元資料標頭之外,每個 Netlink 協議都定義了自己的固定元資料標頭。(類似於網路標頭的堆疊方式 - 乙太網 > IP > TCP,我們有 Netlink > 通用 N. > Family。)

Netlink 訊息始終以 struct nlmsghdr 開頭,後跟特定於協議的標頭。對於通用 Netlink,協議標頭是 struct genlmsghdr。

在通用 Netlink 的情況下,欄位的實際含義如下

struct nlmsghdr {
      __u32   nlmsg_len;      /* Length of message including headers */
      __u16   nlmsg_type;     /* Generic Netlink Family (subsystem) ID */
      __u16   nlmsg_flags;    /* Flags - request or dump */
      __u32   nlmsg_seq;      /* Sequence number */
      __u32   nlmsg_pid;      /* Port ID, set to 0 */
};
struct genlmsghdr {
      __u8    cmd;            /* Command, as defined by the Family */
      __u8    version;        /* Irrelevant, set to 1 */
      __u16   reserved;       /* Reserved, set to 0 */
};
/* TLV attributes follow... */

在經典 Netlink 中,nlmsghdr.nlmsg_type 用於標識訊息引用的子系統中的哪個操作(例如,獲取有關 netdev 的資訊)。通用 Netlink 需要在單個協議中多路複用多個子系統,因此它使用此欄位來標識子系統,而 genlmsghdr.cmd 則用於標識操作。(有關如何查詢感興趣的子系統的 Family ID 的資訊,請參閱 解析 Family ID。)請注意,此欄位的前 16 個值 (0 - 15) 保留用於經典 Netlink 和通用 Netlink 中的控制訊息。有關更多詳細資訊,請參閱 Netlink 訊息型別。

Netlink 套接字上有 3 種常見的訊息交換型別

  • 執行單個操作 (do);

  • 轉儲資訊 (dump);

  • 獲取非同步通知 (multicast)。

經典 Netlink 非常靈活,並且可能允許發生其他型別的交換,但在實踐中,這些是使用的三種類型。

非同步通知由核心傳送,並由訂閱它們的使用者套接字接收。do 和 dump 請求由使用者發起。nlmsghdr.nlmsg_flags 應按如下方式設定

  • 對於 do:NLM_F_REQUEST | NLM_F_ACK

  • 對於 dump:NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP

nlmsghdr.nlmsg_seq 應設定為單調遞增的值。該值在響應中被回顯,並且在實踐中並不重要,但是為傳送的每條訊息將其設定為遞增的值被認為是良好的習慣。該欄位的目的是將響應與請求進行匹配。非同步通知的 nlmsghdr.nlmsg_seq 將為 0。

nlmsghdr.nlmsg_pid 是 Netlink 中地址的等效項。在與核心通訊時,此欄位可以設定為 0。有關該欄位的(不常見)用途,請參閱 nlmsg_pid。

genlmsghdr.version 的預期用途是允許對子系統提供的 API 進行版本控制。迄今為止,沒有子系統對此欄位進行了重大使用,因此將其設定為 1 似乎是一個安全的選擇。

Netlink 訊息型別¶

如前所述,nlmsghdr.nlmsg_type 攜帶特定於協議的值,但是前 16 個識別符號是保留的(第一個特定於子系統的訊息型別應等於 NLMSG_MIN_TYPE,即 0x10)。

僅定義了 4 個 Netlink 控制訊息

  • NLMSG_NOOP - 忽略訊息,在實踐中未使用;

  • NLMSG_ERROR - 攜帶操作的返回程式碼;

  • NLMSG_DONE - 標記轉儲的結束;

  • NLMSG_OVERRUN - 套接字緩衝區已溢位,迄今為止未使用。

NLMSG_ERROR 和 NLMSG_DONE 具有實際意義。它們攜帶操作的返回程式碼。請注意,除非在請求上設定了 `NLM_F_ACK` 標誌,否則如果沒有錯誤,Netlink 將不會以 `NLMSG_ERROR` 進行響應。為了避免必須特殊處理此怪癖,建議始終設定 `NLM_F_ACK`。

`NLMSG_ERROR` 的格式由 struct nlmsgerr 描述

----------------------------------------------
| struct nlmsghdr - response header          |
----------------------------------------------
|    int error                               |
----------------------------------------------
| struct nlmsghdr - original request header |
----------------------------------------------
| ** optionally (1) payload of the request   |
----------------------------------------------
| ** optionally (2) extended ACK             |
----------------------------------------------

這裡有兩個 `struct nlmsghdr` 例項,第一個是響應,第二個是請求。NLMSG_ERROR 攜帶導致錯誤的訊息的資訊。這在嘗試將請求與響應進行匹配或重新解析請求以將其轉儲到日誌中時可能很有用。

請求的有效負載不會在報告成功的訊息中(`error == 0`)或如果設定了 `NETLINK_CAP_ACK` setsockopt() 時回顯。後者很常見,也許建議這樣做,因為必須從核心讀取每個請求的副本是相當浪費的。請求有效負載的缺失由 `nlmsghdr.nlmsg_flags` 中的 `NLM_F_CAPPED` 指示。

`NLMSG_ERROR` 的第二個可選元素是擴充套件 ACK 屬性。有關更多詳細資訊,請參閱 `擴充套件 ACK`。擴充套件 ACK 的存在由 `nlmsghdr.nlmsg_flags` 中的 `NLM_F_ACK_TLVS` 指示。

NLMSG_DONE 更簡單,請求永遠不會被回顯,但是可能存在擴充套件 ACK 屬性

----------------------------------------------
| struct nlmsghdr - response header          |
----------------------------------------------
|    int error                               |
----------------------------------------------
| ** optionally extended ACK                 |
----------------------------------------------

請注意,某些實現可能會發出自定義 `NLMSG_DONE` 訊息來回復 `do` 操作請求。在這種情況下,有效負載是特定於實現的,並且也可能不存在。

解析 Family ID¶

本節解釋瞭如何查詢子系統的 Family ID。它也可以作為通用 Netlink 通訊的示例。

通用 Netlink 本身是一個透過通用 Netlink API 公開的子系統。為了避免迴圈依賴,通用 Netlink 具有靜態分配的 Family ID(`GENL_ID_CTRL` 等於 `NLMSG_MIN_TYPE`)。通用 Netlink family 實現了一個命令,用於查詢有關其他 family 的資訊(`CTRL_CMD_GETFAMILY`)。

要獲取有關通用 Netlink family(例如名為 `"test1"`)的資訊,我們需要在先前開啟的通用 Netlink 套接字上傳送訊息。該訊息應以通用 Netlink Family (1) 為目標,成為對 `CTRL_CMD_GETFAMILY` 的 `do` (2) 呼叫 (3)。此呼叫的 `dump` 版本將使核心響應有關它知道的 _所有_ family 的資訊。最後但並非最不重要的是,必須將所討論的 family 的名稱 (4) 指定為具有適當型別的屬性

struct nlmsghdr:
  __u32 nlmsg_len:    32
  __u16 nlmsg_type:   GENL_ID_CTRL               // (1)
  __u16 nlmsg_flags:  NLM_F_REQUEST | NLM_F_ACK  // (2)
  __u32 nlmsg_seq:    1
  __u32 nlmsg_pid:    0

struct genlmsghdr:
  __u8 cmd:           CTRL_CMD_GETFAMILY         // (3)
  __u8 version:       2 /* or 1, doesn't matter */
  __u16 reserved:     0

struct nlattr:                                   // (4)
  __u16 nla_len:      10
  __u16 nla_type:     CTRL_ATTR_FAMILY_NAME
  char data:          test1\0

(padding:)
  char data:          \0\0

Netlink 中的長度欄位(`nlmsghdr.nlmsg_len` 和 `nlattr.nla_len`)始終 _包括_ 標頭。netlink 中的屬性標頭必須與從訊息開始處的 4 個位元組對齊,因此在 `CTRL_ATTR_FAMILY_NAME` 之後新增額外的 `\0\0`。屬性長度 _不包括_ 填充。

如果找到了 family,核心將回復兩條訊息,即包含有關 family 所有資訊的響應

/* Message #1 - reply */
struct nlmsghdr:
  __u32 nlmsg_len:    136
  __u16 nlmsg_type:   GENL_ID_CTRL
  __u16 nlmsg_flags:  0
  __u32 nlmsg_seq:    1    /* echoed from our request */
  __u32 nlmsg_pid:    5831 /* The PID of our user space process */

struct genlmsghdr:
  __u8 cmd:           CTRL_CMD_GETFAMILY
  __u8 version:       2
  __u16 reserved:     0

struct nlattr:
  __u16 nla_len:      10
  __u16 nla_type:     CTRL_ATTR_FAMILY_NAME
  char data:          test1\0

(padding:)
  data:               \0\0

struct nlattr:
  __u16 nla_len:      6
  __u16 nla_type:     CTRL_ATTR_FAMILY_ID
  __u16:              123  /* The Family ID we are after */

(padding:)
  char data:          \0\0

struct nlattr:
  __u16 nla_len:      9
  __u16 nla_type:     CTRL_ATTR_FAMILY_VERSION
  __u16:              1

/* ... etc, more attributes will follow. */

以及錯誤程式碼(成功),因為在請求上已設定 `NLM_F_ACK`

/* Message #2 - the ACK */
struct nlmsghdr:
  __u32 nlmsg_len:    36
  __u16 nlmsg_type:   NLMSG_ERROR
  __u16 nlmsg_flags:  NLM_F_CAPPED /* There won't be a payload */
  __u32 nlmsg_seq:    1    /* echoed from our request */
  __u32 nlmsg_pid:    5831 /* The PID of our user space process */

int error:            0

struct nlmsghdr: /* Copy of the request header as we sent it */
  __u32 nlmsg_len:    32
  __u16 nlmsg_type:   GENL_ID_CTRL
  __u16 nlmsg_flags:  NLM_F_REQUEST | NLM_F_ACK
  __u32 nlmsg_seq:    1
  __u32 nlmsg_pid:    0

屬性(struct nlattr)的順序無法保證,因此使用者必須遍歷屬性並解析它們。

請注意,通用 Netlink 套接字未與單個 family 關聯或繫結。套接字可以用於與許多不同的 family 交換訊息,使用 `nlmsghdr.nlmsg_type` 欄位在逐條訊息的基礎上選擇接收 family。

擴充套件 ACK¶

擴充套件 ACK 控制在 `NLMSG_ERROR` 和 `NLMSG_DONE` 訊息中報告附加的錯誤/警告 TLV。為了保持向後相容性,必須透過將 `NETLINK_EXT_ACK` setsockopt() 設定為 `1` 來顯式啟用此功能。

擴充套件 ack 屬性的型別在 `enum nlmsgerr_attrs` 中定義。最常用的屬性是 `NLMSGERR_ATTR_MSG`、`NLMSGERR_ATTR_OFFS` 和 `NLMSGERR_ATTR_MISS_*`。

`NLMSGERR_ATTR_MSG` 攜帶一條英文訊息,描述遇到的問題。這些訊息比可以透過標準 UNIX 錯誤程式碼表達的訊息詳細得多。

`NLMSGERR_ATTR_OFFS` 指向導致問題的屬性。

`NLMSGERR_ATTR_MISS_TYPE` 和 `NLMSGERR_ATTR_MISS_NEST` 告知缺少屬性。

擴充套件 ACK 可以在錯誤以及成功的情況下報告。後者應被視為警告。

擴充套件 ACK 極大地提高了 Netlink 的可用性,並且應始終啟用、適當地解析並報告給使用者。

高階主題¶

轉儲一致性¶

核心用於儲存物件的一些資料結構使得很難提供轉儲中所有物件的原子快照(而不影響更新它們的快速路徑)。

如果轉儲被中斷並且可能不一致(例如,缺少物件),核心可能會在轉儲中的任何訊息(包括 `NLMSG_DONE` 訊息)上設定 `NLM_F_DUMP_INTR` 標誌。如果使用者空間看到設定了該標誌,則應重試轉儲。

內省¶

透過訪問在 `解析 Family ID` 中報告的 Family 物件來啟用基本內省功能。使用者可以查詢有關通用 Netlink family 的資訊,包括核心支援的操作和核心理解的屬性。Family 資訊包括核心可以解析的屬性的最高 ID,單獨的命令(`CTRL_CMD_GETPOLICY`)提供了有關支援的屬性的詳細資訊,包括核心接受的值範圍。

在使用者空間需要確保核心在發出請求之前支援某項功能的情況下,查詢 family 資訊很有用。

nlmsg_pid¶

nlmsghdr.nlmsg_pid 是 Netlink 中地址的等效項。它被稱為埠 ID,有時也稱為程序 ID,因為出於歷史原因,如果應用程式未選擇(bind() 到)顯式埠 ID,則核心將自動為其分配等於其程序 ID 的 ID(如 getpid() 系統呼叫所報告的)。

與 TCP/IP 網路協議的 bind() 語義類似,零值表示“自動分配”,因此應用程式通常將 `nlmsghdr.nlmsg_pid` 欄位初始化為 `0`。

當核心需要傳送單播通知時,該欄位今天仍然在極少數情況下使用。使用者空間應用程式可以使用 bind() 將其套接字與特定的 PID 關聯,然後將其 PID 傳遞給核心。這樣,核心就可以到達特定的使用者空間程序。

這種通訊在 UMH(使用者模式助手)之類的場景中得到利用,當核心需要觸發使用者空間處理或向用戶空間詢問策略決策時。

多播通知¶

Netlink 的優勢之一是能夠向用戶空間傳送事件通知。這是一種單向通訊形式(核心 -> 使用者),不涉及任何控制訊息,例如 `NLMSG_ERROR` 或 `NLMSG_DONE`。

例如,通用 Netlink family 本身定義了一組關於已註冊 family 的多播通知。新增新 family 時,已訂閱通知的套接字將收到以下訊息

struct nlmsghdr:
  __u32 nlmsg_len:    136
  __u16 nlmsg_type:   GENL_ID_CTRL
  __u16 nlmsg_flags:  0
  __u32 nlmsg_seq:    0
  __u32 nlmsg_pid:    0

struct genlmsghdr:
  __u8 cmd:           CTRL_CMD_NEWFAMILY
  __u8 version:       2
  __u16 reserved:     0

struct nlattr:
  __u16 nla_len:      10
  __u16 nla_type:     CTRL_ATTR_FAMILY_NAME
  char data:          test1\0

(padding:)
  data:               \0\0

struct nlattr:
  __u16 nla_len:      6
  __u16 nla_type:     CTRL_ATTR_FAMILY_ID
  __u16:              123  /* The Family ID we are after */

(padding:)
  char data:          \0\0

struct nlattr:
  __u16 nla_len:      9
  __u16 nla_type:     CTRL_ATTR_FAMILY_VERSION
  __u16:              1

/* ... etc, more attributes will follow. */

該通知包含與對 `CTRL_CMD_GETFAMILY` 請求的響應相同的資訊。

通知的 Netlink 標頭大多為 0 且不相關。`nlmsghdr.nlmsg_seq` 可以為零,也可以是 family 維護的單調遞增的通知序列號。

要接收通知,使用者套接字必須訂閱相關的通知組。與 Family ID 非常相似,給定多播組的 Group ID 是動態的,可以在 Family 資訊中找到。`CTRL_ATTR_MCAST_GROUPS` 屬性包含具有組的名稱(`CTRL_ATTR_MCAST_GRP_NAME`)和 ID(`CTRL_ATTR_MCAST_GRP_ID`)的巢狀。

一旦知道 Group ID,setsockopt() 呼叫會將套接字新增到組中

unsigned int group_id;

/* .. find the group ID... */

setsockopt(fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP,
           &group_id, sizeof(group_id));

套接字現在將接收通知。

建議使用單獨的套接字來接收通知和向核心傳送請求。通知的非同步性質意味著它們可能會與響應混合在一起,從而使訊息處理變得更加困難。

緩衝區大小調整¶

Netlink 套接字是資料報套接字而不是流套接字,這意味著每條訊息都必須透過單個 recv()/recvmsg() 系統呼叫完整地接收。如果使用者提供的緩衝區太短,則訊息將被截斷,並且在 struct msghdr 中設定 `MSG_TRUNC` 標誌(struct msghdr 是 recvmsg() 系統呼叫的第二個引數,_不是_ Netlink 標頭)。

截斷時,訊息的剩餘部分將被丟棄。

Netlink 期望使用者緩衝區至少為 8kB 或 CPU 架構的頁面大小,以較大者為準。但是,特定的 Netlink family 可能需要更大的緩衝區。建議使用 32kB 緩衝區來最有效地處理轉儲(更大的緩衝區可以容納更多轉儲的物件,因此需要更少的 recvmsg() 呼叫)。

經典 Netlink¶

經典 Netlink 和通用 Netlink 之間的主要區別在於子系統識別符號的動態分配和內省的可用性。從理論上講,該協議沒有顯著差異,但是,在實踐中,經典 Netlink 嘗試了一些在通用 Netlink 中被放棄的概念(實際上,它們通常只在單個子系統的一小部分中找到用途)。本節旨在解釋其中的一些概念,其明確目標是讓通用 Netlink 使用者在閱讀 uAPI 標頭時有信心忽略它們。

這裡的大多數概念和示例都指的是 `NETLINK_ROUTE` family,它涵蓋了 Linux 網路堆疊的大部分配置。對該 family 的真實文件,值得單獨寫一章(或一本書)。

Family¶

Netlink 將子系統稱為 family。這是使用套接字和協議 family 概念的殘餘,協議 family 是 `NETLINK_ROUTE` 中訊息多路分解的一部分。

可悲的是,每一層封裝都喜歡將它攜帶的任何東西稱為“family”,這使得這個術語非常令人困惑

  1. AF_NETLINK 是一個真正的套接字協議 family

  2. AF_NETLINK 的文件將訊息中自身標頭(`struct nlmsghdr`)後面的內容稱為“Family 標頭”

  3. 通用 Netlink 是 AF_NETLINK 的一個 family(struct genlmsghdr 遵循 `struct nlmsghdr`),但它也稱其使用者為“Family”。

請注意,通用 Netlink Family ID 位於不同的“ID 空間”中,並且與經典 Netlink 協議號重疊(例如,`NETLINK_CRYPTO` 的經典 Netlink 協議 ID 為 21,通用 Netlink 也會很高興地將其分配給它的一個 family)。

嚴格檢查¶

`NETLINK_GET_STRICT_CHK` 套接字選項啟用 `NETLINK_ROUTE` 中的嚴格輸入檢查。之所以需要它,是因為歷史上核心沒有驗證它沒有處理的結構的欄位。這使得以後開始使用這些欄位變得不可能,而不會冒應用程式錯誤初始化或根本不初始化它們的風險。

`NETLINK_GET_STRICT_CHK` 宣告應用程式正在正確初始化所有欄位。它還選擇驗證訊息是否不包含尾隨資料,並請求核心拒絕型別高於核心已知的最大屬性型別的屬性。

`NETLINK_GET_STRICT_CHK` 不在 `NETLINK_ROUTE` 之外使用。

未知屬性¶

歷史上,Netlink 忽略了所有未知屬性。想法是它可以讓應用程式無需探測核心支援的內容。應用程式可以發出更改狀態的請求,並檢查請求的哪些部分“卡住了”。

對於新的通用 Netlink family 和選擇嚴格檢查的 family 來說,情況不再如此。有關執行的驗證型別,請參見 enum netlink_validation。

固定元資料和結構¶

經典 Netlink 在訊息中大量使用了固定格式的結構。訊息通常在 `struct nlmsghdr` 之後有一個包含相當數量欄位的結構。也很常見的是將具有多個成員的結構放入屬性中,而不將每個成員分解為它自己的屬性。

這導致了驗證和可擴充套件性的問題,因此對於新屬性,不再鼓勵使用二進位制結構。

請求型別¶

`NETLINK_ROUTE` 將請求分為 4 種類型 `NEW`、`DEL`、`GET` 和 `SET`。每個物件都可以處理所有或某些請求(物件是 netdev、路由、地址、qdisc 等)。請求型別由訊息型別的最低 2 位定義,因此新物件的命令將始終以 4 的步幅分配。

每個物件還將具有所有請求型別共享的自己的固定元資料(例如,用於 netdev 請求的 struct ifinfomsg,用於地址請求的 struct ifaddrmsg,用於 qdisc 請求的 struct tcmsg)。

即使其他協議和通用 Netlink 命令經常在其訊息名稱中使用相同的動詞(`GET`、`SET`),請求型別的概念也沒有得到更廣泛的採用。

通知回顯¶

`NLM_F_ECHO` 請求用於請求的回撥通知被排隊到請求套接字上。這對於發現請求的影響很有用。

請注意,此功能不是普遍實現的。

其他特定於請求型別的標誌¶

經典 Netlink 在 `struct nlmsghdr` 中定義了 nlmsg_flags 上位元組中 `GET`、`NEW` 和 `DEL` 請求的各種標誌。由於請求型別尚未被概括化,因此特定於請求型別的標誌很少使用(並且被認為對於新 family 來說已棄用)。

對於 `GET` - `NLM_F_ROOT` 和 `NLM_F_MATCH` 被合併為 `NLM_F_DUMP`,並且不單獨使用。`NLM_F_ATOMIC` 從未使用過。

對於 `DEL` - `NLM_F_NONREC` 僅由 nftables 使用,而 `NLM_F_BULK` 僅由 FDB 的某些操作使用。

用於 `NEW` 的標誌在經典 Netlink 中最常用。不幸的是,其含義並不十分清楚。以下描述基於對作者意圖的最佳猜測,並且在實踐中,所有 family 都以某種方式偏離它。`NLM_F_REPLACE` 要求替換現有物件,如果沒有匹配的物件存在,則操作應失敗。`NLM_F_EXCL` 具有相反的語義,並且只有在物件已經存在時才成功。`NLM_F_CREATE` 要求如果物件不存在則建立該物件,它可以與 `NLM_F_REPLACE` 和 `NLM_F_EXCL` 結合使用。

主 Netlink uAPI 標頭中的註釋說明

4.4BSD ADD           NLM_F_CREATE|NLM_F_EXCL
4.4BSD CHANGE        NLM_F_REPLACE

True CHANGE          NLM_F_CREATE|NLM_F_REPLACE
Append               NLM_F_CREATE
Check                NLM_F_EXCL

這似乎表明這些標誌早於請求型別。沒有 `NLM_F_CREATE` 的 `NLM_F_REPLACE` 最初用於代替 `SET` 命令。沒有 `NLM_F_CREATE` 的 `NLM_F_EXCL` 用於檢查物件是否存在而不建立它,大概早於 `GET` 命令。

`NLM_F_APPEND` 指示如果一個鍵可以具有與其關聯的多個物件(例如,路由的多個下一跳物件),則應將新物件新增到列表中,而不是替換整個列表。

uAPI 參考¶

struct nlmsghdr¶

Netlink 訊息的固定格式元資料標頭

定義:

struct nlmsghdr {
    __u32 nlmsg_len;
    __u16 nlmsg_type;
    __u16 nlmsg_flags;
    __u32 nlmsg_seq;
    __u32 nlmsg_pid;
};

成員

nlmsg_len

訊息長度(包括標頭)

nlmsg_type

訊息內容型別

nlmsg_flags

附加標誌

nlmsg_seq

序列號

nlmsg_pid

傳送程序埠 ID

enum nlmsgerr_attrs¶

nlmsgerr 屬性

常量

NLMSGERR_ATTR_UNUSED

未使用

NLMSGERR_ATTR_MSG

錯誤訊息字串(字串)

NLMSGERR_ATTR_OFFS

原始訊息中無效屬性的偏移量,從標頭開始計數 (u32)

NLMSGERR_ATTR_COOKIE

任意特定於子系統的 cookie,用於(在成功情況下)標識建立的物件或操作或類似的東西(二進位制)

NLMSGERR_ATTR_POLICY

拒絕屬性的策略

NLMSGERR_ATTR_MISS_TYPE

缺失的必需屬性的型別,如果屬性在訊息級別缺失,則不會出現 `NLMSGERR_ATTR_MISS_NEST`

NLMSGERR_ATTR_MISS_NEST

屬性缺失的巢狀的偏移量

__NLMSGERR_ATTR_MAX

屬性數量

NLMSGERR_ATTR_MAX

最高屬性編號

enum netlink_attribute_type¶

屬性型別

常量

NL_ATTR_TYPE_INVALID

未使用

NL_ATTR_TYPE_FLAG

標誌屬性(存在/不存在)

NL_ATTR_TYPE_U8

8 位無符號屬性

NL_ATTR_TYPE_U16

16 位無符號屬性

NL_ATTR_TYPE_U32

32 位無符號屬性

NL_ATTR_TYPE_U64

64 位無符號屬性

NL_ATTR_TYPE_S8

8 位有符號屬性

NL_ATTR_TYPE_S16

16 位有符號屬性

NL_ATTR_TYPE_S32

32 位有符號屬性

NL_ATTR_TYPE_S64

64 位有符號屬性

NL_ATTR_TYPE_BINARY

二進位制資料,可以指定最小/最大長度

NL_ATTR_TYPE_STRING

字串,可以指定最小/最大長度

NL_ATTR_TYPE_NUL_STRING

NUL 終止字串,可以指定最小/最大長度

NL_ATTR_TYPE_NESTED

巢狀,即此屬性的內容由子屬性組成。可以指定巢狀策略和內部的最大型別。

NL_ATTR_TYPE_NESTED_ARRAY

巢狀陣列,即此屬性的內容包含子屬性,其型別無關緊要(僅用於分隔陣列條目),並且每個此類陣列條目再次具有屬性,可以指定這些內部屬性的策略和相應的最大型別。

NL_ATTR_TYPE_BITFIELD32

struct nla_bitfield32 屬性

NL_ATTR_TYPE_SINT

32 位或 64 位有符號屬性,對齊到 4B

NL_ATTR_TYPE_UINT

32 位或 64 位無符號屬性,對齊到 4B

enum netlink_policy_type_attr¶

策略型別屬性

常量

NL_POLICY_TYPE_ATTR_UNSPEC

未使用

NL_POLICY_TYPE_ATTR_TYPE

屬性的型別,enum netlink_attribute_type (U32)

NL_POLICY_TYPE_ATTR_MIN_VALUE_S

有符號整數的最小值 (S64)

NL_POLICY_TYPE_ATTR_MAX_VALUE_S

有符號整數的最大值 (S64)

NL_POLICY_TYPE_ATTR_MIN_VALUE_U

無符號整數的最小值 (U64)

NL_POLICY_TYPE_ATTR_MAX_VALUE_U

無符號整數的最大值 (U64)

NL_POLICY_TYPE_ATTR_MIN_LENGTH

二進位制屬性的最小長度,如果未給定則沒有最小值 (U32)

NL_POLICY_TYPE_ATTR_MAX_LENGTH

二進位制屬性的最大長度,如果未給定則沒有最大值 (U32)

NL_POLICY_TYPE_ATTR_POLICY_IDX

巢狀和巢狀陣列型別的子策略 (U32)

NL_POLICY_TYPE_ATTR_POLICY_MAXTYPE

巢狀和巢狀陣列型別的最大子策略屬性,理論上可以小於索引指向的策略的大小,如果在巢狀內限制 (U32)

NL_POLICY_TYPE_ATTR_BITFIELD32_MASK

bitfield32 型別的有效掩碼 (U32)

NL_POLICY_TYPE_ATTR_PAD

用於 64 位對齊的填充屬性

NL_POLICY_TYPE_ATTR_MASK

無符號整數的有效位掩碼 (U64)

__NL_POLICY_TYPE_ATTR_MAX

屬性數量

NL_POLICY_TYPE_ATTR_MAX

最高屬性編號

©核心開發社群。 | 由 Sphinx 5.3.0 & Alabaster 0.7.16 驅動 | 頁面原始碼