操作状态

1. 简介

Linux 区分接口的管理状态和操作状态。管理状态是“ip link set dev <dev> up 或 down”的结果,反映了管理员是否希望使用该设备进行流量传输。

然而,一个接口并不仅仅因为管理员启用它就可以使用 - 以太网需要插入交换机,并且根据站点的网络策略和配置,需要执行 802.1X 身份验证才能传输用户数据。操作状态显示接口传输此用户数据的能力。

由于 802.1X,必须允许用户空间影响操作状态。为了适应这一点,操作状态分为两个部分:两个只能由驱动程序设置的标志,以及一个与 RFC2863 兼容的状态,该状态从这些标志、策略派生而来,并且在某些规则下可以从用户空间更改。

2. 从用户空间查询

管理状态和操作状态都可以通过 netlink 操作 RTM_GETLINK 查询。也可以订阅 RTNLGRP_LINK 以在接口管理启用时接收更新通知。这对于从用户空间设置很重要。

这些值包含接口状态

ifinfomsg::if_flags & IFF_UP

接口管理启用

ifinfomsg::if_flags & IFF_RUNNING

接口处于 RFC2863 操作状态 UP 或 UNKNOWN。这是为了向后兼容,路由守护进程、dhcp 客户端可以使用此标志来确定是否应使用该接口。

ifinfomsg::if_flags & IFF_LOWER_UP

驱动程序已发出 netif_carrier_on() 信号

ifinfomsg::if_flags & IFF_DORMANT

驱动程序已发出 netif_dormant_on() 信号

TLV IFLA_OPERSTATE

包含接口的 RFC2863 状态的数值表示

IF_OPER_UNKNOWN (0)

接口处于未知状态,驱动程序和用户空间都没有设置操作状态。必须考虑将接口用于用户数据,因为并非每个驱动程序都实现了设置操作状态。

IF_OPER_NOTPRESENT (1)

在当前内核中未使用(不存在的接口通常会消失),只是一个数值占位符。

IF_OPER_DOWN (2)

接口无法在 L1 上传输数据,例如以太网未插入或接口管理关闭。

IF_OPER_LOWERLAYERDOWN (3)

堆叠在 IF_OPER_DOWN 接口上的接口显示此状态(例如 VLAN)。

IF_OPER_TESTING (4)

接口处于测试模式,例如执行驱动程序自检或介质(电缆)测试。在测试完成之前,它不能用于正常流量。

IF_OPER_DORMANT (5)

接口 L1 已启动,但正在等待外部事件,例如协议建立。(802.1X)

IF_OPER_UP (6)

接口已操作启动,可以使用。

此 TLV 也可以通过 sysfs 查询。

TLV IFLA_LINKMODE

包含链接策略。这是下面描述的用户空间交互所必需的。

此 TLV 也可以通过 sysfs 查询。

3. 内核驱动程序 API

内核驱动程序可以访问映射到 IFF_LOWER_UP 和 IFF_DORMANT 的两个标志。这些标志可以从任何地方设置,甚至可以从中断中设置。保证只有驱动程序具有写访问权限,但是,如果驱动程序的不同层操作同一标志,则驱动程序必须提供所需的同步。

__LINK_STATE_NOCARRIER,映射到 !IFF_LOWER_UP

驱动程序使用 netif_carrier_on() 清除此标志,并使用 netif_carrier_off() 设置此标志。在 netif_carrier_off() 上,调度程序停止发送数据包。“载波”的名称和反转是历史遗留问题,可以将其视为底层。

请注意,对于某些类型的软设备,它们不管理任何真正的硬件,可以从用户空间设置此位。应该使用 TLV IFLA_CARRIER 来执行此操作。

netif_carrier_ok() 可用于查询该位。

__LINK_STATE_DORMANT,映射到 IFF_DORMANT

由驱动程序设置以表示该设备尚不能使用,因为必须完成一些驱动程序控制的协议建立。相应的函数为 netif_dormant_on() 用于设置标志,netif_dormant_off() 用于清除标志,netif_dormant() 用于查询标志。

在设备分配时,标志 __LINK_STATE_NOCARRIER 和 __LINK_STATE_DORMANT 都被清除,因此有效状态等效于 netif_carrier_ok() 和 !netif_dormant()

每当驱动程序更改这些标志之一时,都会调度一个工作队列事件,以将标志组合转换为 IFLA_OPERSTATE,如下所示

!netif_carrier_ok()

如果接口堆叠,则为 IF_OPER_LOWERLAYERDOWN,否则为 IF_OPER_DOWN。内核可以识别堆叠的接口,因为它们的 ifindex != iflink。

netif_carrier_ok() && netif_dormant()

IF_OPER_DORMANT

netif_carrier_ok() && !netif_dormant()

如果禁用用户空间交互,则为 IF_OPER_UP。否则为 IF_OPER_DORMANT,用户空间可以在之后启动 IF_OPER_UP 转换。

4. 从用户空间设置

应用程序必须使用 netlink 接口来影响接口的 RFC2863 操作状态。通过 RTM_SETLINK 将 IFLA_LINKMODE 设置为 1 指示内核,当驱动程序设置 netif_carrier_ok() && !netif_dormant() 的组合时,接口应进入 IF_OPER_DORMANT 而不是 IF_OPER_UP。之后,只要驱动程序不设置 netif_carrier_off()netif_dormant_on(),用户空间应用程序可以将 IFLA_OPERSTATE 设置为 IF_OPER_DORMANT 或 IF_OPER_UP。用户空间所做的更改会在 netlink 组 RTNLGRP_LINK 上进行多播。

因此,基本上 802.1X 请求者与内核的交互方式如下

  • 订阅 RTNLGRP_LINK

  • 通过 RTM_SETLINK 将 IFLA_LINKMODE 设置为 1

  • 查询一次 RTM_GETLINK 以获取初始状态

  • 如果初始标志不是(IFF_LOWER_UP && !IFF_DORMANT),请等待 netlink 多播发出此状态信号

  • 执行 802.1X,如果标志再次下降,则最终中止

  • 如果身份验证成功,则发送 RTM_SETLINK 以将操作状态设置为 IF_OPER_UP,否则设置为 IF_OPER_DORMANT

  • 查看操作状态和 IFF_RUNNING 如何通过 netlink 多播回显

  • 如果 802.1X 重新身份验证失败,则将接口设置回 IF_OPER_DORMANT

  • 如果内核更改 IFF_LOWER_UP 或 IFF_DORMANT 标志,则重新启动

如果请求者关闭,请将 IFLA_LINKMODE 带回 0,并将 IFLA_OPERSTATE 带回一个合理的值。

路由守护程序或 dhcp 客户端只需关心 IFF_RUNNING 或等待操作状态变为 IF_OPER_UP/IF_OPER_UNKNOWN,然后再考虑接口/查询 DHCP 地址。

如有技术问题和/或意见,请发送电子邮件至 Stefan Rompf (stefan at loplof.de)。