使用 Netlink 協議規範¶
本文件是使用 Netlink 協議規範的快速入門指南。 有關規範的更詳細描述,請參見 Netlink 協議規範 (YAML 格式)。
簡單 CLI¶
核心自帶一個簡單的 CLI 工具,在開發 Netlink 相關程式碼時應該很有用。 該工具用 Python 實現,可以使用 YAML 規範向核心發出 Netlink 請求。 僅支援通用 Netlink。
該工具位於 tools/net/ynl/pyynl/cli.py。 它接受一些引數,其中最重要的引數是
--spec- 指向規範檔案
--do $name/--dump $name- 發出請求$name
--json $attrs- 為請求提供屬性
--subscribe $group- 接收來自$group的通知
YAML 規範可以在 Documentation/netlink/specs/ 下找到。
使用示例
$ ./tools/net/ynl/pyynl/cli.py --spec Documentation/netlink/specs/ethtool.yaml \
--do rings-get \
--json '{"header":{"dev-index": 18}}'
{'header': {'dev-index': 18, 'dev-name': 'eni1np1'},
'rx': 0,
'rx-jumbo': 0,
'rx-jumbo-max': 4096,
'rx-max': 4096,
'rx-mini': 0,
'rx-mini-max': 4096,
'tx': 0,
'tx-max': 4096,
'tx-push': 0}
輸入引數被解析為 JSON,而輸出僅是 Python 格式化的。 這是因為某些 Netlink 型別不能直接表示為 JSON。 如果輸入中需要這些屬性,則需要對指令碼進行一些 hacking。
規範和 Netlink 內部結構被分解為一個獨立的庫 - 重用 cli.py 中的程式碼應該很容易編寫 Python 工具/測試。
生成核心程式碼¶
tools/net/ynl/ynl-regen.sh 掃描核心樹以查詢需要更新的自動生成的檔案。 使用此工具是生成/更新自動生成程式碼的最簡單方法。
預設情況下,只有在規範比原始檔更新時才會重新生成程式碼,要強制重新生成,請使用 -f。
ynl-regen.sh 在檔案中搜索 YNL-GEN(請注意,它只掃描 git 索引中的檔案,即僅掃描 git 跟蹤的檔案!)。 例如,fou_nl.c 核心原始檔包含
/* Documentation/netlink/specs/fou.yaml */
/* YNL-GEN kernel source */
ynl-regen.sh 將找到此標記並使用基於 fou.yaml 的核心原始檔替換該檔案。
基於規範生成新檔案的最簡單方法是將上面兩個標記行新增到檔案中,將該檔案新增到 git,然後執行重新生成工具。 在樹中 Grep YNL-GEN 以檢視其他示例。
程式碼生成本身由 tools/net/ynl/pyynl/ynl_gen_c.py 執行,但它需要一些引數,因此直接為每個檔案呼叫它很快就會變得乏味。
YNL lib¶
tools/net/ynl/lib/ 包含一個 C 庫(基於 libmnl)的實現,該庫與 tools/net/ynl/pyynl/ynl_gen_c.py 生成的程式碼整合,以建立易於使用的 netlink 封裝器。
YNL 基礎知識¶
YNL 庫由兩部分組成 - 通用程式碼(函式以 ynl_ 為字首)和每個系列的自動生成程式碼(以系列名稱為字首)。
要建立 YNL 套接字,請呼叫 ynl_sock_create() 並傳遞系列結構(系列結構由自動生成的程式碼匯出)。 ynl_sock_destroy() 關閉套接字。
YNL 請求¶
發出 YNL 請求的步驟最好用一個示例來解釋。 此示例中的所有函式和型別都來自自動生成的程式碼(在本例中是 netdev 系列)
// 0. Request and response pointers
struct netdev_dev_get_req *req;
struct netdev_dev_get_rsp *d;
// 1. Allocate a request
req = netdev_dev_get_req_alloc();
// 2. Set request parameters (as needed)
netdev_dev_get_req_set_ifindex(req, ifindex);
// 3. Issues the request
d = netdev_dev_get(ys, req);
// 4. Free the request arguments
netdev_dev_get_req_free(req);
// 5. Error check (the return value from step 3)
if (!d) {
// 6. Print the YNL-generated error
fprintf(stderr, "YNL: %s\n", ys->err.msg);
return -1;
}
// ... do stuff with the response @d
// 7. Free response
netdev_dev_get_rsp_free(d);
YNL 轉儲¶
執行轉儲的模式與請求類似。 轉儲返回一個物件列表,該列表由特殊標記終止,或者在出錯時返回 NULL。 使用 ynl_dump_foreach() 迭代結果。
YNL 通知¶
YNL lib 支援使用同一個套接字進行通知和請求。 如果在處理請求期間收到通知,它們將在內部排隊,並可以在稍後檢索。
要訂閱通知,請使用 ynl_subscribe()。 必須從套接字中讀取通知,ynl_socket_get_fd() 返回底層套接字 fd,該 fd 可以插入到適當的非同步 IO API(如 poll 或 select)中。
可以使用 ynl_ntf_dequeue() 檢索通知,並且必須使用 ynl_ntf_free() 釋放通知。 由於我們事先不知道通知型別,因此通知作為 struct ynl_ntf_base_type * 返回,並且使用者應該基於 cmd 成員將其轉換為適當的完整型別。