目录

1、初始化

2、开启watchdog

3、超时处理dev_watchdog

4、发送时间trans_start 更新

5、usbnet驱动


网络设备watchdog用于监控网卡驱动发送数据是否异常,如果异常就报错,并调用网卡驱动提供的超时处理函数。

基本原理:网卡设备初始化时,初始化watchdog定时器,用户空间打开网卡设备时,同时开启watchdog定时器,每次watchdog定时器超时,就检查网卡设备的发送队列发送数据是否超时,如果超时报错并调用网卡驱动提供的超时处理函数。 然后重启watchdog定时器超时。

驱动位置:

linux3.10.xx 
netdevice.h 
\net\core\dev.c 
\net\sched\sch_generic.c

1、初始化

网卡驱动在register_netdevice注册网络设备时,调用dev_init_scheduler初始化watchdog定时器,register_netdevice---->dev_init_scheduler

void dev_init_scheduler(struct net_device *dev)
{dev->qdisc = &noop_qdisc;netdev_for_each_tx_queue(dev, dev_init_scheduler_queue, &noop_qdisc);if (dev_ingress_queue(dev))dev_init_scheduler_queue(dev, dev_ingress_queue(dev), &noop_qdisc);setup_timer(&dev->watchdog_timer, dev_watchdog, (unsigned long)dev); 初始化watchdog_timer
}

2、开启watchdog

网卡up时,开启watchdog。
__dev_change_flags–>__dev_open–>dev_activate(dev);

void dev_activate(struct net_device *dev)
{int need_watchdog;/* No queueing discipline is attached to device;create default one i.e. pfifo_fast for devices,which need queueing and noqueue_qdisc forvirtual interfaces*/if (dev->qdisc == &noop_qdisc) //流控策略初始化时为noop_qdiscattach_default_qdiscs(dev); //改变流控测试为默认pfifo_fastif (!netif_carrier_ok(dev))/* Delay activation until next carrier-on event */return;need_watchdog = 0;netdev_for_each_tx_queue(dev, transition_one_qdisc, &need_watchdog);// 判断是否开启watchdog,不为noqueue_qdisc,就开启watchdogif (dev_ingress_queue(dev))transition_one_qdisc(dev, dev_ingress_queue(dev), NULL);if (need_watchdog) {//前面判断开启dev->trans_start = jiffies; //记录开启时间dev_watchdog_up(dev); //开启watchdog}
}static void transition_one_qdisc(struct net_device *dev,struct netdev_queue *dev_queue,void *_need_watchdog)
{struct Qdisc *new_qdisc = dev_queue->qdisc_sleeping;int *need_watchdog_p = _need_watchdog;if (!(new_qdisc->flags & TCQ_F_BUILTIN))clear_bit(__QDISC_STATE_DEACTIVATED, &new_qdisc->state);rcu_assign_pointer(dev_queue->qdisc, new_qdisc);if (need_watchdog_p && new_qdisc != &noqueue_qdisc) { //不为noqueue_qdisc,就开启watchdogdev_queue->trans_start = 0;*need_watchdog_p = 1;}
}

dev_watchdog_up(dev); 开启watchdog

static void dev_watchdog_up(struct net_device *dev)
{__netdev_watchdog_up(dev);
}void __netdev_watchdog_up(struct net_device *dev)
{if (dev->netdev_ops->ndo_tx_timeout) {//ndo_tx_timeout为网卡驱动提供的发送超时处理函数if (dev->watchdog_timeo <= 0)dev->watchdog_timeo = 5*HZ; //默认超时处理 5*HZif (!mod_timer(&dev->watchdog_timer,round_jiffies(jiffies + dev->watchdog_timeo))) //开启定时器dev_hold(dev);}
}

3、超时处理dev_watchdog

dev_watchdog为watchdog定时器超时处理函数,只有网卡还在正常运行时,才进一步检查网卡发送队列是否超时。
判断发送队列是否超时:
1,netif_xmit_stopped发送队列已经停止
2,txq->trans_start最近一次发送数据的时间已经超过watchdog_timeo时间

static void dev_watchdog(unsigned long arg)
{struct net_device *dev = (struct net_device *)arg;netif_tx_lock(dev);判断if (!qdisc_tx_is_noop(dev)) { txq->qdisc不是noop_qdisc,if (netif_device_present(dev) &&  网卡设备还存在netif_running(dev) && 网卡设备还在运行netif_carrier_ok(dev)) { 网卡设备在线int some_queue_timedout = 0;unsigned int i;unsigned long trans_start;for (i = 0; i < dev->num_tx_queues; i++) {struct netdev_queue *txq;txq = netdev_get_tx_queue(dev, i);/** old device drivers set dev->trans_start*/trans_start = txq->trans_start ? : dev->trans_start; 记录最近一次网卡设备发送时间if (netif_xmit_stopped(txq) &&  网卡发送队列在运行,time_after(jiffies, (trans_start +dev->watchdog_timeo))) {  当前时间已经超过了最近一次网卡设备发送时间+watchdog_timeosome_queue_timedout = 1;txq->trans_timeout++;break;}}if (some_queue_timedout) { 超时后,告警,并调用网卡驱动的ndo_tx_timeoutWARN_ONCE(1, KERN_INFO "NETDEV WATCHDOG: %s (%s): transmit queue %u timed out\n",dev->name, netdev_drivername(dev), i);dev->netdev_ops->ndo_tx_timeout(dev);}if (!mod_timer(&dev->watchdog_timer,round_jiffies(jiffies +dev->watchdog_timeo)))重新开启定时器dev_hold(dev);}}netif_tx_unlock(dev);dev_put(dev);
}

网卡在open时,网卡驱动提供的ndo_open都会调用netif_start_queue (net); 开启网卡队列,这样dev_watchdog函数中netif_xmit_stopped返回0,就不会判断是否超时。网卡在异常或发送队列中长度超过了门限时会停止发送队列netif_xmit_stopped,netif_xmit_stopped就返回1,那就进一步判断最近一次发送数据时间是否超时。

enum netdev_queue_state_t {__QUEUE_STATE_DRV_XOFF,__QUEUE_STATE_STACK_XOFF,__QUEUE_STATE_FROZEN,
#define QUEUE_STATE_ANY_XOFF ((1 << __QUEUE_STATE_DRV_XOFF)        | \(1 << __QUEUE_STATE_STACK_XOFF))
#define QUEUE_STATE_ANY_XOFF_OR_FROZEN (QUEUE_STATE_ANY_XOFF        | \(1 << __QUEUE_STATE_FROZEN))
};

ndo_open都会调用netif_start_queue (net),清除__QUEUE_STATE_DRV_XOFF

static inline void netif_tx_start_queue(struct netdev_queue *dev_queue)
{clear_bit(__QUEUE_STATE_DRV_XOFF, &dev_queue->state);
}static inline void netif_start_queue(struct net_device *dev)
{netif_tx_start_queue(netdev_get_tx_queue(dev, 0));
}

网卡在异常或发送队列中长度超过了门限时会停止发送队列netif_stop_queue,设置__QUEUE_STATE_DRV_XOFF

static inline void netif_tx_stop_queue(struct netdev_queue *dev_queue)
{if (WARN_ON(!dev_queue)) {pr_info("netif_stop_queue() cannot be called before register_netdev()\n");return;}set_bit(__QUEUE_STATE_DRV_XOFF, &dev_queue->state);
}/***    netif_stop_queue - stop transmitted packets*    @dev: network device**    Stop upper layers calling the device hard_start_xmit routine.*    Used for flow control when transmit resources are unavailable.*/
static inline void netif_stop_queue(struct net_device *dev)
{netif_tx_stop_queue(netdev_get_tx_queue(dev, 0));
}

判断是否停止,__QUEUE_STATE_DRV_XOFF

static inline bool netif_xmit_stopped(const struct netdev_queue *dev_queue)
{return dev_queue->state & QUEUE_STATE_ANY_XOFF;
}

4、发送时间trans_start 更新

dev_hard_start_xmit调用网卡驱动接口ndo_start_xmit发送完成数据后,调用txq_trans_update更新发送时间。

dev_hard_start_xmit:rc = ops->ndo_start_xmit(skb, dev);if (rc == NETDEV_TX_OK)txq_trans_update(txq);static inline void txq_trans_update(struct netdev_queue *txq)
{if (txq->xmit_lock_owner != -1)txq->trans_start = jiffies;
}

5、usbnet驱动

usbnet_open–>netif_start_queue (net);

发送完成回调函数中tx_complete调用netif_stop_queue

tx_completecase -EPROTO:case -ETIME:case -EILSEQ:usb_mark_last_busy(dev->udev);if (!timer_pending (&dev->delay)) {mod_timer (&dev->delay,jiffies + THROTTLE_JIFFIES);netif_dbg(dev, link, dev->net,"tx throttle %d\n", urb->status); }netif_stop_queue (dev->net); 异常停止发送队列break;

usbnet_start_xmit发送数据中,发送队列数据格式超过了门限

usbnet_start_xmitcase 0:net->trans_start = jiffies;更新每次发送数据更新发送时间__usbnet_queue_skb(&dev->txq, skb, tx_start);if (dev->txq.qlen >= TX_QLEN (dev)) 超过门限netif_stop_queue (net);

网卡驱动dev_watchdog详解相关推荐

  1. 解决网络时断时续:Nvidia-NFORCE-nvnet.ko网卡驱动安装详解

    解决网络时断时续:Nvidia-NFORCE-nvnet.ko网卡驱动安装详解 作者: spyer 高级会员(IPLogged) 日期: 2006-10-23 13:57:11 前天在ASUS-A8N ...

  2. linux如何安装网卡驱动6,详解CentOS 6.5如何安装Realtek无线网卡驱动

    一.安装前的准备工作 [a] 检查无线网卡驱动的安装情况(通过查看网络接口的安装情况来检查) 在虚拟终端下输入: #> iwconfig 若显示如下信息,则表示未安装无线网卡驱动 lo no w ...

  3. 《Linux设备驱动开发详解(第2版)》隆重出版

    Linux设备驱动开发详解(第2版)(前一版狂销3万册,畅销书最新升级) [新品] 点击看大图     基本信息 * 作者: 宋宝华       * 出版社:人民邮电出版社     * ISBN:97 ...

  4. 计算机驱动安装的几个方法,安装驱动方法详解

    欢迎大家来到学习啦,本文为大家讲解安装驱动方法详解,欢迎大家阅读借鉴. 买电脑时一般都会送驱动盘的,那里面都是各种驱动,显卡应该是单独的一个驱动盘,主要的驱动无非有这几种:声卡,显卡,网卡,声卡和网卡 ...

  5. Linux双网卡绑定bond详解

    Linux双网卡绑定bond详解 bond 网卡bond是通过多张网卡绑定为一个逻辑网卡,实现本地网卡的冗余,带宽扩容和负载均衡,在生产场景中是一种常用的技术 通过以下命令确定内核是否支持 bondi ...

  6. 《Linux设备驱动开发详解 A》一一2.3 接口与总线

    本节书摘来华章计算机出版社<Linux设备驱动开发详解 A>一书中的第2章,第2.3节,作者:宋宝华 更多章节内容可以访问云栖社区"华章计算机"公众号查看.1 2.3 ...

  7. linux设备驱动开发详解源码,linux设备驱动开发详解光盘源码.rar

    压缩包 : linux设备驱动开发详解光盘源码.rar 列表 19/busybox源代码/busybox-1.2.1.tar.bz2 19/MTD工具/mtd-utils-1.0.0.tar.gz 1 ...

  8. linux中流设备_[快速上手Linux设备驱动]之块设备驱动流程详解一

    [快速上手Linux设备驱动]之块设备驱动流程详解一 walfred已经在[快速上手Linux设备驱动]之我看字符设备驱动一 文中详细讲解了linux下字符设备驱动,并紧接着用四篇文章描述了Linux ...

  9. 《Linux设备驱动开发详解》学习笔记一

    Linux设备驱动开发详解学习笔记<一> 书名:<Linux设备驱动开发详解>第二版 主机环境:Linux version 2.6.25-14.fc9.i686@Fedora ...

最新文章

  1. 相关性分析p值_一行代码掌握皮尔逊相关分析,洞察变量关系
  2. python给excel排序_如何使用Python对Excel工作表排序
  3. 如何对 Kubernetes 进行扩展
  4. 微软宣布 Windows 10X:用于可折叠 PC 的新操作系统
  5. 微信 android 省略号,安卓版微信再现重大Bug,点击链接直接崩溃
  6. LeetCode 236. 二叉树的最近公共祖先(递归)
  7. win10 打开注册表
  8. asp.net中使用FreeTextBox控件
  9. MyBatis mysql 字符串拼接
  10. Python数据挖掘实战-唐宇迪-专题视频课程
  11. 小学生计算机应用教学ppt,小学计算机课件ppt
  12. 儿童python编程书籍推荐_推荐给家长们的《趣学Python——教孩子学编程》书
  13. 照片查看器无法打开此图片 因为计算机上,Win7查看图片时提示Windows照片查看器无法打开此图片解决方法...
  14. 苹果AppStore应用商店生存之道以及市场攻略最全解析
  15. ToC产品和ToB产品的区别
  16. 小程序图表wx-chart
  17. android apk汉化与破解
  18. 页框,页表,页表项,页面大小,页表项 长度的理解
  19. 【转】日常电脑操作应该注意的十几个小动作以及维
  20. win10开始菜单 此计算机,主编解决win10开始菜单出现ms-resource:AppListName的详尽操作步骤...

热门文章

  1. .dat数据文件怎么打开_SPSS统计分析,之一 SPSS数据文件读取
  2. C++中的四种强制类型转换
  3. asp.net实现显示在线会员
  4. 佳能6D2相机断电DAT文件修复后没有声音怎么处理解决
  5. 微信小程序源码大集004---小程序实现大转盘 仿天猫抽奖 跑马灯效果(有图有源码)
  6. Masonry使用中equalTo和mas_equalTo的区别
  7. 惠普M1213打印机如何关闭打印状态消息
  8. 中国大学排名定向爬虫以及淘宝商品爬虫参考嵩天老师Python爬虫课程遇到的问题及解决
  9. C#之CAD二次开发实例 (13) 图层操作
  10. rm: invalid option -- ‘n‘和mv: invalid option -- ‘s‘