操作状态¶
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 上传输数据,例如,以太网未插入或接口已禁用 ADMIN。
- 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()
上,调度程序停止发送数据包。 名称“carrier”和反转是历史遗留的,可以将其视为下层。
请注意,对于某些类型的软设备,它们不管理任何真正的硬件,可以从用户空间设置此位。 应该使用 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 以将 operstate 设置为 IF_OPER_UP,否则设置为 IF_OPER_DORMANT
查看 operstate 和 IFF_RUNNING 如何通过 netlink 多播回显
如果 802.1X 重新身份验证失败,则将接口设置回 IF_OPER_DORMANT
如果内核更改 IFF_LOWER_UP 或 IFF_DORMANT 标志,则重新启动
如果请求者停止运行,则将 IFLA_LINKMODE 带回 0,并将 IFLA_OPERSTATE 设置为合理值。
路由守护进程或 dhcp 客户端只需要注意 IFF_RUNNING 或等待 operstate 转到 IF_OPER_UP/IF_OPER_UNKNOWN,然后才考虑接口/查询 DHCP 地址。
如有技术问题和/或意见,请发送电子邮件至 Stefan Rompf (stefan at loplof.de)。