操作状态¶
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)。