Logo

Linux 内核

6.13.0-rc6

快速搜索

目录

  • 开发流程
  • 提交补丁
  • 行为准则
  • 维护者手册
  • 所有开发流程文档
  • 核心 API
  • 驱动 API
  • 子系统
  • 锁
  • 许可规则
  • 编写文档
  • 开发工具
  • 测试指南
  • 黑客指南
  • 追踪
  • 故障注入
  • 热补丁
  • Rust
  • 管理
  • 构建系统
  • 报告问题
  • 用户空间工具
  • 用户空间 API
    • 系统调用
    • 安全相关接口
    • 设备和 I/O
    • 其他
      • Linux 特定的 ELF 特性
      • Netlink 手册
      • 平台配置文件选择(例如 /sys/firmware/acpi/platform_profile)
      • VDUSE - “用户空间中的 vDPA 设备”
      • futex2
      • Perf 环形缓冲区
  • 固件
  • 固件和设备树
  • 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 还为 “dumping” 提供了自然支持,即向用户空间通信某种类型的所有对象(例如,dumping 所有网络接口)。

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. > 系列。)

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 用于标识消息正在引用的子系统中的哪个操作(例如,获取有关网络设备的信息)。通用 Netlink 需要在一个协议中复用多个子系统,因此它使用此字段来标识子系统,而 genlmsghdr.cmd 则标识操作。(有关如何查找感兴趣子系统的系列 ID 的信息,请参阅 解析系列 ID。)请注意,此字段的前 16 个值(0 - 15)保留用于经典 Netlink 和通用 Netlink 中的控制消息。有关更多详细信息,请参阅 Netlink 消息类型。

Netlink 套接字上有 3 种常见的消息交换类型

  • 执行单个操作 (do);

  • dump 信息 (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 - 标记 dump 的结束;

  • 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 携带有关导致错误的请求的信息。当尝试将请求与响应匹配或重新解析请求以将其 dump 到日志中时,这可能很有用。

请求的有效负载不会在报告成功的消息中回显(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 操作请求。在这种情况下,有效负载是特定于实现的,也可能不存在。

解析系列 ID¶

本节解释如何查找子系统的系列 ID。它也用作通用 Netlink 通信的示例。

通用 Netlink 本身是一个通过通用 Netlink API 公开的子系统。为了避免循环依赖,通用 Netlink 具有静态分配的 Family ID(GENL_ID_CTRL,等于 NLMSG_MIN_TYPE)。通用 Netlink 系列实现了一个命令,用于查找有关其他系列的信息(CTRL_CMD_GETFAMILY)。

要获取有关名为例如 "test1" 的通用 Netlink 系列的信息,我们需要在先前打开的通用 Netlink 套接字上发送消息。该消息应以通用 Netlink 系列 (1) 为目标,是对 CTRL_CMD_GETFAMILY (3) 的 do (2) 调用。此调用的 dump 版本将使内核响应它所知道的所有系列的信息。最后但并非最不重要的是,必须以适当的类型 (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。属性长度不包括填充。

如果找到该系列,内核将回复两条消息,一条是包含该系列所有信息的响应

/* 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

属性(结构体 nlattr)的顺序不能保证,因此用户必须遍历属性并解析它们。

请注意,通用 Netlink 套接字不与单个系列关联或绑定。一个套接字可以用于与许多不同的系列交换消息,使用 nlmsghdr.nlmsg_type 字段在逐条消息的基础上选择接收方系列。

扩展 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 系列的信息,包括内核支持哪些操作以及内核理解哪些属性。系列信息包括内核可以解析的属性的最高 ID,一个单独的命令(CTRL_CMD_GETPOLICY)提供有关受支持属性的详细信息,包括内核接受的值的范围。

在用户空间需要确保内核支持某个功能然后再发出请求的情况下,查询系列信息非常有用。

nlmsg_pid¶

nlmsghdr.nlmsg_pid 是 Netlink 等效于地址的概念。它被称为 Port ID,有时也被称为 Process ID,因为由于历史原因,如果应用程序不选择(绑定到)显式 Port ID,内核将自动为其分配一个等于其 Process ID 的 ID(如 getpid() 系统调用报告的那样)。

与 TCP/IP 网络协议的 bind() 语义类似,零值表示“自动分配”,因此应用程序通常将 nlmsghdr.nlmsg_pid 字段初始化为 0。

该字段在今天仍然在内核需要发送单播通知的极少数情况下使用。用户空间应用程序可以使用 bind() 将其套接字与特定的 PID 关联,然后将其 PID 传递给内核。这样,内核就可以到达特定的用户空间进程。

当内核需要触发用户空间处理或向用户空间请求策略决策时,在类似 UMH(用户模式助手)的场景中会使用这种通信。

多播通知¶

Netlink 的优势之一是能够向用户空间发送事件通知。这是一种单向通信形式(内核 -> 用户),不涉及任何控制消息,如 NLMSG_ERROR 或 NLMSG_DONE。

例如,通用 Netlink 系列本身定义了一组关于已注册系列的多播通知。当添加新系列时,订阅通知的套接字将收到以下消息

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 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 系列可能需要更大的缓冲区。建议使用 32kB 缓冲区来最有效地处理转储(更大的缓冲区可以容纳更多转储的对象,因此需要更少的 recvmsg() 调用)。

经典 Netlink¶

经典 Netlink 和通用 Netlink 之间的主要区别在于子系统标识符的动态分配和自省的可用性。理论上,协议没有显着差异,但是,实际上,经典 Netlink 尝试了一些在通用 Netlink 中被放弃的概念(实际上,它们通常只在单个子系统的某个小角落中找到用途)。本节旨在解释其中一些概念,其明确目标是让通用 Netlink 用户在阅读 uAPI 标头时有信心忽略它们。

这里的大多数概念和示例都指的是 NETLINK_ROUTE 系列,它涵盖了 Linux 网络堆栈的大部分配置。该系列的真实文档值得单独一章(或一本书)。

系列¶

Netlink 将子系统称为系列。这是使用套接字和协议系列概念的遗留问题,协议系列是 NETLINK_ROUTE 中消息多路分解的一部分。

可悲的是,每一层封装都喜欢将其携带的内容称为“系列”,这使得这个术语非常混乱

  1. AF_NETLINK 是一个真正的套接字协议系列

  2. AF_NETLINK 的文档将其自身头部(struct nlmsghdr)之后的消息内容称为“族头部”。

  3. 通用 Netlink 是 AF_NETLINK 的一个族(struct genlmsghdr 紧随 struct nlmsghdr 之后),但它也称其用户为“族”。

请注意,通用 Netlink 族 ID 位于不同的“ID 空间”中,并与经典 Netlink 协议号重叠(例如,NETLINK_CRYPTO 的经典 Netlink 协议 ID 为 21,而通用 Netlink 也会将其分配给其某个族)。

严格检查¶

NETLINK_GET_STRICT_CHK 套接字选项在 NETLINK_ROUTE 中启用严格的输入检查。之所以需要它,是因为历史上内核不会验证它不处理的结构的字段。这使得以后开始使用这些字段变得不可能,而不会冒应用程序不正确初始化或根本不初始化这些字段的风险。

NETLINK_GET_STRICT_CHK 声明应用程序正在正确初始化所有字段。它还选择验证消息是否不包含尾随数据,并请求内核拒绝类型高于内核已知最大属性类型的属性。

NETLINK_GET_STRICT_CHK 不在 NETLINK_ROUTE 之外使用。

未知属性¶

历史上,Netlink 忽略所有未知属性。当时的考虑是,这可以使应用程序不必探测内核支持什么。应用程序可以发出更改状态的请求,并检查请求的哪些部分“生效”了。

对于新的通用 Netlink 族以及选择加入严格检查的族,情况不再如此。请参阅枚举 netlink_validation 以了解执行的验证类型。

固定元数据和结构¶

经典 Netlink 在消息中大量使用固定格式的结构。消息通常在 struct nlmsghdr 之后包含具有大量字段的结构。也常见将具有多个成员的结构放入属性中,而不将每个成员分解为其自身的属性。

这导致了验证和可扩展性方面的问题,因此强烈建议不要将二进制结构用于新属性。

请求类型¶

NETLINK_ROUTE 将请求分为 4 种类型:NEW、DEL、GET 和 SET。每个对象都可以处理所有或部分这些请求(对象包括 netdevs、路由、地址、qdiscs 等)。请求类型由消息类型的最低 2 位定义,因此新对象的命令始终以 4 的步幅分配。

每个对象还具有所有请求类型共享的自己的固定元数据(例如,用于 netdev 请求的 struct ifinfomsg,用于地址请求的 struct ifaddrmsg,用于 qdisc 请求的 struct tcmsg)。

尽管其他协议和通用 Netlink 命令在其消息名称中经常使用相同的动词(GET、SET),但请求类型的概念并未得到更广泛的采用。

通知回显¶

请求 NLM_F_ECHO 将请求产生的通知排队到请求套接字上。这有助于发现请求的影响。

请注意,此功能并非普遍实现。

其他特定于请求类型的标志¶

经典 Netlink 在 struct nlmsghdr 中的 nlmsg_flags 的高字节中为其 GET、NEW 和 DEL 请求定义了各种标志。由于请求类型尚未被普遍化,因此特定于请求类型的标志很少使用(并且被认为对新族已弃用)。

对于 GET - NLM_F_ROOT 和 NLM_F_MATCH 合并为 NLM_F_DUMP,不再单独使用。NLM_F_ATOMIC 从未使用。

对于 DEL - NLM_F_NONREC 仅由 nftables 使用,而 NLM_F_BULK 仅由 FDB 的某些操作使用。

NEW 的标志在经典 Netlink 中最常用。不幸的是,含义并不十分明确。以下描述基于作者意图的最佳猜测,并且实际上所有族都以某种方式偏离了它。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

嵌套,即此属性的内容由子属性组成。可以指定嵌套策略和内部 maxtype。

NL_ATTR_TYPE_NESTED_ARRAY

嵌套数组,即此属性的内容包含子属性,其类型无关紧要(仅用于分隔数组条目),并且每个此类数组条目又具有属性,可以指定这些内部属性的策略和相应的 maxtype。

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 强力驱动 | 页面源文件