[openwrt]mt7621网卡实现对 ethtool rx-checksum on/off的支持

公司低端产品使用openwrt定制的mips架构设备,在一个项目中出现了网卡大量丢包问题。使用ethtool -S eth0 查看详细统计,发现 rx_checksum_errors 大量上涨。
用户业务比较特殊,使用了私有协议。报文二层ethernet的type是0x0800,表示3层是ip协议,但是三层报文不是ip报文,而是用户的私有协议。
在这里插入图片描述

初步推断是网卡将私有协议当作ip协议进行校验,校验值错误从而将报文丢弃。
为了验证问题,使用 ethtool -K eth0 rx-checksum off 将网卡的收报校验关闭,发现问题依然存在。

难道是推断错误?不太可能,明明统计的就是 rx_checksum_errors。
突然想到,是不是 网卡没有支持rx-checksum开关,导致 ethtool -K eth0 rx-checksum off 命令没有生效?

ethtool工具在内核中是通过 dev_ioctl–>dev_ethtool–>通过ethcmd 来进行对应处理。
为了快速确认 ethtool -K eth0 rx-checksum off 具体使用了哪个ethcmd,我使用funchook 模块,在dev_ethtool 函数前后增加了debug信息,编译并加载hook ko后,在测试centos机器上执行 ethtool -K eth0 rx-checksum off,
通过log发现,该命令调用了多个 ethcmd,但实际使用的是 ETHTOOL_SFEATURES 来设置开关。
ethtool_set_features–>__netdev_update_features–>

	if (dev->netdev_ops->ndo_set_features)
		err = dev->netdev_ops->ndo_set_features(dev, features);
	else
		err = 0;

查到这里发现,如果网卡设备没有定义 ndo_set_features 函数的话,则直接返回0。从结果上看好像成功了,但是网卡什么操作没有做。

查看网卡驱动代码,找到 fe_netdev_ops 定义,发现确实没有定义 ndo_set_features 函数。这是ethtool 关闭rx-checksum无效的根本原因。

static const struct net_device_ops fe_netdev_ops = {
	.ndo_init		= fe_init,
	.ndo_uninit		= fe_uninit,
	.ndo_open		= fe_open,
	.ndo_stop		= fe_stop,
	.ndo_start_xmit		= fe_start_xmit,
	.ndo_set_mac_address	= fe_set_mac_address,
	.ndo_validate_addr	= eth_validate_addr,
	.ndo_do_ioctl		= fe_do_ioctl,
	.ndo_change_mtu		= fe_change_mtu,
	.ndo_tx_timeout		= fe_tx_timeout,
	.ndo_get_stats64        = fe_get_stats64,
	.ndo_vlan_rx_add_vid	= fe_vlan_rx_add_vid,
	.ndo_vlan_rx_kill_vid	= fe_vlan_rx_kill_vid,
#ifdef CONFIG_NET_POLL_CONTROLLER
	.ndo_poll_controller	= fe_poll_controller,
#endif
};

查阅了驱动的相关代码,写了个 ndo_set_features 的实现。

static int fe_set_features(struct net_device *dev,
                             netdev_features_t features)
{
	struct fe_priv *priv = netdev_priv(dev);
	const struct of_device_id *match = of_match_device(of_fe_match, priv->device);
	struct fe_soc_data *soc = (struct fe_soc_data *)match->data;
	netdev_features_t changed = features ^ dev->features;

	if (!(changed & NETIF_F_RXCSUM))
		return 0;

	dev->features = features;	//更新features
	soc->fwd_config(priv);		//使用fwd_config回调函数来更新设置

	return 0;
}

更新后的驱动,可以通过 ethtool -K eth0 rx-checksum on/off 来开启/关闭网卡的rx-checksum功能。

如果遇到类似问题,想打patch的话,可以使用以下patch文件。

diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
old mode 100644
new mode 100755
index 8c71a92..770cd6b
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -1392,6 +1392,26 @@ static int fe_change_mtu(struct net_device *dev, int new_mtu)
        return fe_open(dev);
 }
 
+static int fe_set_features(struct net_device *dev,
+                             netdev_features_t features)
+{
+       struct fe_priv *priv = netdev_priv(dev);
+       const struct of_device_id *match = of_match_device(of_fe_match, priv->device);
+       struct fe_soc_data *soc = (struct fe_soc_data *)match->data;
+       netdev_features_t changed = features ^ dev->features;
+
+       if (!(changed & NETIF_F_RXCSUM))
+               return 0;
+
+       dev->features = features;
+       soc->fwd_config(priv);
+
+       return 0;
+}
+
+
 static const struct net_device_ops fe_netdev_ops = {
        .ndo_init               = fe_init,
        .ndo_uninit             = fe_uninit,
@@ -1409,6 +1429,7 @@ static const struct net_device_ops fe_netdev_ops = {
 #ifdef CONFIG_NET_POLL_CONTROLLER
        .ndo_poll_controller    = fe_poll_controller,
 #endif
+       .ndo_set_features = fe_set_features,
 };
 
 static void fe_reset_pending(struct fe_priv *priv)

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

浮沉飘摇

码字不易,打赏随意。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值