linux 3.16.35 内核不支持 ethtool 获取 virtio 接口速率双工
问题描述
linux-3.16.35 内核虚拟化环境中,管理口使用 virtio 网卡,执行 ethtool 获取信息,有如下信息:
[root] # ethtool enps0f0
Settings for enps0f0:
Link detected: yes
获取的信息中缺少速率双工的状态,这说明此版本内核 virtio-net 驱动代码中 ethtool_ops xxx_get_settings 类别的接口没有实现。
内核代码中的相关信息
3.16.35 内核中 virtio-net 驱动 ethtool_ops 实现代码:
static const struct ethtool_ops virtnet_ethtool_ops = {
.get_drvinfo = virtnet_get_drvinfo,
.get_link = ethtool_op_get_link,
.get_ringparam = virtnet_get_ringparam,
.set_channels = virtnet_set_channels,
.get_channels = virtnet_get_channels,
};
确认 virtio-net 实现的 ethtool_ops 中未注册 get_settings 接口,故而不能获取到速率双工。
如何修复?
考虑到我们使用 virtio-net 作为管理口的场景中获取到的速率双工只用于展示,没有其它用途,决定自己实现一个非常简单的版本。
查看内核 git log 中的相关修改,发现有写固定值的实现,最新的实现通过读取后端信息来获取,相对复杂,最终决定使用如下代码解决此问题:
Index: virtio_net.c
===================================================================
--- virtio_net.c
+++ virtio_net.c
@@ -1314,12 +1314,30 @@
channels->other_count = 0;
}
+static int virtnet_get_link_settings(struct net_device *dev,
+ struct ethtool_cmd *cmd)
+{
+ cmd->speed = SPEED_UNKNOWN;
+ cmd->autoneg = AUTONEG_DISABLE;
+ cmd->supported = SUPPORTED_10000baseT_Full;
+ cmd->port = PORT_OTHER;
+ cmd->duplex = DUPLEX_UNKNOWN;
+
+ if (netif_running(dev)) {
+ ethtool_cmd_speed_set(cmd, SPEED_10000);
+ cmd->duplex = DUPLEX_FULL;
+ }
+
+ return 0;
+}
+
static const struct ethtool_ops virtnet_ethtool_ops = {
.get_drvinfo = virtnet_get_drvinfo,
.get_link = ethtool_op_get_link,
.get_ringparam = virtnet_get_ringparam,
.set_channels = virtnet_set_channels,
.get_channels = virtnet_get_channels,
+ .get_settings = virtnet_get_link_settings,
};
上述逻辑为当接口状态 RUNNING 的时候,返回 10G 速率与全双工,当接口状态 down 的时候,返回未知速率与半双工模式。
实现了一个 virtnet_get_link_settings 注册到 virtnet_ethtool_ops get_settings 虚函数中就能够正常获取 virtio-net 网卡的速率双工。
测试记录
重新编译然后加载 virtio_net 后的状态:
[root] # ethtool eth0
Settings for eth0:
Supported ports: [ ]
Supported link modes: 10000baseT/Full
Supported pause frame use: No
Supports auto-negotiation: No
Advertised link modes: Not reported
Advertised pause frame use: No
Advertised auto-negotiation: No
Speed: Unknown!
Duplex: Unknown! (255)
Port: Other
PHYAD: 0
Transceiver: internal
Auto-negotiation: off
Link detected: no
接口 up 时获取的状态:
[root] # ethtool eth0
Settings for eth0:
Supported ports: [ ]
Supported link modes: 10000baseT/Full
Supported pause frame use: No
Supports auto-negotiation: No
Advertised link modes: Not reported
Advertised pause frame use: No
Advertised auto-negotiation: No
Speed: 10000Mb/s
Duplex: Full
Port: Other
PHYAD: 0
Transceiver: internal
Auto-negotiation: off
Link detected: yes
接口 down 了后的状态:
[root] # ifconfig eth0 down
[root] # ethtool eth0
Settings for eth0:
Supported ports: [ ]
Supported link modes: 10000baseT/Full
Supported pause frame use: No
Supports auto-negotiation: No
Advertised link modes: Not reported
Advertised pause frame use: No
Advertised auto-negotiation: No
Speed: Unknown!
Duplex: Unknown! (255)
Port: Other
PHYAD: 0
Transceiver: internal
Auto-negotiation: off
Link detected: no
测试通过!
一点插曲
写的过程中纠结了下要返回的速率是千兆还是万兆的问题,认知中应该是千兆,但是阅读高版本的代码却发现返回的是万兆,经过一通搜索后确定 virtio-net 网卡的速率是万兆而非千兆。
修复了这个问题后发布给产品,产品对于获取到的速率是万兆也有疑问,于是澄清了下,果然很多人都认为 virtio-net 虚拟网卡的速率应该是千兆呀。