网络设备之侦测连接状态

通常,网络设备会定时地侦测设备是否处于可传递状态。当状态发生变化时,会调用netif_carrier_on或者netif_carrier_off来通知内核;

从网上设备插拔网线或者另一端的设备关闭或禁止,都会导致连接状态改变;

netif_carrier_on----设备驱动侦测到设备传递信号时调用

netif_carrier_off----设备驱动侦测到设备丢失信号时调用

上述两个状态改变函数均会调用linkwatch_fire_event将事件加入到事件队列进行调度;

(netif_carrier_on | netif_carrier_off)

|--->linkwatch_fire_event

linkwatch_fire_event

|---->linkwatch_urgent_event

|---->linkwatch_add_event

|---->linkwatch_schedule_work---->linkwatch_event---->__linkwatch_run_queue

|---->linkwatch_do_dev

 1 /**
 2  *    netif_carrier_on - set carrier
 3  *    @dev: network device
 4  *
 5  * Device has detected that carrier.
 6  */
 7 /* 侦测到设备传递信号时调用 */
 8 void netif_carrier_on(struct net_device *dev)
 9 {
10     /* 清除nocarrier标记 */
11     if (test_and_clear_bit(__LINK_STATE_NOCARRIER, &dev->state)) {
12         /* 设备尚未注册,则返回 */
13         if (dev->reg_state == NETREG_UNINITIALIZED)
14             return;
15         /* 增加状态改变次数 */
16         atomic_inc(&dev->carrier_changes);
17         /* 加入事件处理队列进行处理 */
18         linkwatch_fire_event(dev);
19         /* 若设备正在运行 */
20         if (netif_running(dev))
21             /* 启动软件狗 */
22             __netdev_watchdog_up(dev);
23     }
24 }
 1 /**
 2  *    netif_carrier_off - clear carrier
 3  *    @dev: network device
 4  *
 5  * Device has detected loss of carrier.
 6  */
 7 /* 侦测到设备丢失信号时调用 */
 8 void netif_carrier_off(struct net_device *dev)
 9 {
10     /* 设置nocarrier状态 */
11     if (!test_and_set_bit(__LINK_STATE_NOCARRIER, &dev->state)) {
12         /* 设备尚未注册,则返回 */
13         if (dev->reg_state == NETREG_UNINITIALIZED)
14             return;
15         /* 增加设备改变状态 */
16         atomic_inc(&dev->carrier_changes);
17         /* 加入事件处理队列进行处理 */
18         linkwatch_fire_event(dev);
19     }
20 }
 1 /* 加入事件队列处理 */
 2 void linkwatch_fire_event(struct net_device *dev)
 3 {
 4     /* 判断是否是紧急处理的事件 */
 5     bool urgent = linkwatch_urgent_event(dev);
 6
 7     /* 设置待处理事件标记 */
 8     if (!test_and_set_bit(__LINK_STATE_LINKWATCH_PENDING, &dev->state)) {
 9         /* 添加事件到事件列表 */
10         linkwatch_add_event(dev);
11     }
12     /* 设备以前已经设置了pending标记,不是紧急事件,直接返回 */
13     else if (!urgent)
14         return;
15
16     /* 事件调度 */
17     linkwatch_schedule_work(urgent);
18 }
 1 /* 是否需要紧急处理的事件 */
 2 static bool linkwatch_urgent_event(struct net_device *dev)
 3 {
 4     /* 设备未运行,非紧急 */
 5     if (!netif_running(dev))
 6         return false;
 7
 8     /* 设备的索引号与连接索引号不等,紧急 */
 9     if (dev->ifindex != dev_get_iflink(dev))
10         return true;
11
12     /* 设备作为team port,紧急 */
13     if (dev->priv_flags & IFF_TEAM_PORT)
14         return true;
15     /* 连接与否 && 发送队列排队规则改变与否 */
16     return netif_carrier_ok(dev) &&    qdisc_tx_changing(dev);
17 }
 1 /* 添加事件 */
 2 static void linkwatch_add_event(struct net_device *dev)
 3 {
 4     unsigned long flags;
 5
 6     spin_lock_irqsave(&lweventlist_lock, flags);
 7     /* 若未添加,则添加设备到事件列表 */
 8     if (list_empty(&dev->link_watch_list)) {
 9         list_add_tail(&dev->link_watch_list, &lweventlist);
10         dev_hold(dev);
11     }
12     spin_unlock_irqrestore(&lweventlist_lock, flags);
13 }
 1 /* 调度事件处理工作队列 */
 2 static void linkwatch_schedule_work(int urgent)
 3 {
 4     unsigned long delay = linkwatch_nextevent - jiffies;
 5
 6     /* 已经设置了紧急标记,则返回 */
 7     if (test_bit(LW_URGENT, &linkwatch_flags))
 8         return;
 9
10     /* Minimise down-time: drop delay for up event. */
11     /* 需要紧急调度 */
12     if (urgent) {
13         /* 之前设置了,则返回 */
14         if (test_and_set_bit(LW_URGENT, &linkwatch_flags))
15             return;
16         /* 未设置紧急,则立即执行 */
17         delay = 0;
18     }
19
20     /* If we wrap around we‘ll delay it by at most HZ. */
21     /* 如果大于1s则立即执行 */
22     if (delay > HZ)
23         delay = 0;
24
25     /*
26      * If urgent, schedule immediate execution; otherwise, don‘t
27      * override the existing timer.
28      */
29     /* 如果设置了紧急标记,则立即执行 */
30     if (test_bit(LW_URGENT, &linkwatch_flags))
31         mod_delayed_work(system_wq, &linkwatch_work, 0);
32     /* 未设置紧急标记,则按照delay执行 */
33     else
34         schedule_delayed_work(&linkwatch_work, delay);
35 }
 1 /*
 2     @urgent_only--1-未到达下一次调度时间
 3                            0-已到达下次调度时间
 4 */
 5 static void __linkwatch_run_queue(int urgent_only)
 6 {
 7     struct net_device *dev;
 8     LIST_HEAD(wrk);
 9
10     /*
11      * Limit the number of linkwatch events to one
12      * per second so that a runaway driver does not
13      * cause a storm of messages on the netlink
14      * socket.  This limit does not apply to up events
15      * while the device qdisc is down.
16      */
17     /* 已达到调度时间 */
18     if (!urgent_only)
19         linkwatch_nextevent = jiffies + HZ;
20     /* Limit wrap-around effect on delay. */
21     /*
22         未到达调度时间,并且下一次调度在当前时间的1s以后
23         那么设置调度时间是当前时间
24     */
25     else if (time_after(linkwatch_nextevent, jiffies + HZ))
26         linkwatch_nextevent = jiffies;
27
28     /* 清除紧急标识 */
29     clear_bit(LW_URGENT, &linkwatch_flags);
30
31     spin_lock_irq(&lweventlist_lock);
32     list_splice_init(&lweventlist, &wrk);
33
34     /* 遍历链表 */
35     while (!list_empty(&wrk)) {
36
37         /* 获取设备 */
38         dev = list_first_entry(&wrk, struct net_device, link_watch_list);
39
40         /* 从链表移除设备 */
41         list_del_init(&dev->link_watch_list);
42
43         /* 未到达调度时间 &&  不需要紧急处理  */
44         if (urgent_only && !linkwatch_urgent_event(dev)) {
45             /* 添加到链表尾部 */
46             list_add_tail(&dev->link_watch_list, &lweventlist);
47             /* 继续处理 */
48             continue;
49         }
50         spin_unlock_irq(&lweventlist_lock);
51         /* 处理设备 */
52         linkwatch_do_dev(dev);
53         spin_lock_irq(&lweventlist_lock);
54     }
55
56     /* 链表有未处理事件,则以非紧急状态调度队列 */
57     if (!list_empty(&lweventlist))
58         linkwatch_schedule_work(0);
59     spin_unlock_irq(&lweventlist_lock);
60 }
 1 /* 处理某个设备的状态改变 */
 2 static void linkwatch_do_dev(struct net_device *dev)
 3 {
 4     /*
 5      * Make sure the above read is complete since it can be
 6      * rewritten as soon as we clear the bit below.
 7      */
 8     smp_mb__before_atomic();
 9
10     /* We are about to handle this device,
11      * so new events can be accepted
12      */
13     /* 清除pending标记 */
14     clear_bit(__LINK_STATE_LINKWATCH_PENDING, &dev->state);
15
16     rfc2863_policy(dev);
17
18     /* 如果设备启动状态 */
19     if (dev->flags & IFF_UP) {
20         /* 链路连接 */
21         if (netif_carrier_ok(dev))
22             /* 启用排队规则 */
23             dev_activate(dev);
24         /* 否则*/
25         else
26             /* 关闭排队规则 */
27             dev_deactivate(dev);
28
29         /* 设备状态改变处理 */
30         netdev_state_change(dev);
31     }
32     dev_put(dev);
33 }
时间: 2024-08-05 07:21:39

网络设备之侦测连接状态的相关文章

TCP/IP连接状态

1.建立连接协议(三次握手)(1)客户端发送一个带SYN标志的TCP报文到服务器.这是三次握手过程中的报文1.(2) 服务器端回应客户端的,这是三次握手中的第2个报文,这个报文同时带ACK标志和SYN标志.因此它表示对刚才客户端SYN报文的回应:同时又标志SYN给客户端,询问客户端是否准备好进行数据通讯.(3) 客户必须再次回应服务段一个ACK报文,这是报文段3.2.连接终止协议(四次握手) 由于TCP连接是全双工的,因此每个方向都必须单独进行关闭.这原则是当一方完成它的数据发送任务后就能发送一

查看mysql连接状态各类参数

命令: show processlist; 如果是root帐号,你能看到所有用户的当前连接.如果是其它普通帐号,只能看到自己占用的连接. show processlist;只列出前100条,如果想全列出请使用show full processlist; mysql> show processlist; 命令: show status; 命令:show status like '%下面变量%'; Aborted_clients 由于客户没有正确关闭连接已经死掉,已经放弃的连接数量. Aborted

TCP连接状态及TIME_WAIT

参考: TCP连接中的TIME_WAIT状态 - sunnydogzhou的专栏 - 博客频道 - CSDN.NET http://blog.csdn.net/sunnydogzhou/article/details/6572071 TCP连接状态详解及TIME_WAIT过多的解决方法_小强_新浪博客 http://blog.sina.com.cn/s/blog_8e5d24890102w9yi.html TCP协议三次握手连接四次握手断开和DOS攻击 - NowOrNever - 博客频道 -

Android判断网络连接状态

需要相关权限 <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/><uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/><uses-permission android:name="android.permission.INTERNET"/

李洪强iOS下的实际网络连接状态检测

iOS下的实际网络连接状态检测 序言 网络连接状态检测对于我们的iOS app开发来说是一个非常通用的需求.为了更好的用户体验,我们会在无网络时展现本地或者缓存的内容,并对用户进行合适的提示.对绝大部分iOS开发者来说,从苹果示例代码改变而来的各种Reachablity框架是实现这个需求的普遍选择,比如这个库.但事实上,基于此方案的所有实现,都无法帮助我们检测真正的网络连接状态,它们能检测的只是本地连接状态:这种情况包括但不限于如下场景: 1.现在很流行的公用wifi,需要网页鉴权,鉴权之前无法

zabbix监控nginx连接状态

zabbix学习笔记:zabbix监控nginx连接状态 zabbix监控nginx zabbix可以监控nginx的状态,关于一个服务的状态可以查看服务本身的状态(版本号.是否开启),还应该关注服务能力(例如以nginx的负载效果:连接数.请求数和句柄数).下面我们使用zabbix监控nginx. nginx的安装 如果想要查看nginx的服务状态,在对nginx进行源码安装的时候要选中–with-http_stub_status_module模块. 1.解压安装包: [[email prot

android检测网络连接状态示例讲解

网络的时候,并不是每次都能连接到网络,因此在程序启动中需要对网络的状态进行判断,如果没有网络则提醒用户进行设置 Android连接首先,要判断网络状态,需要有相应的权限,下面为权限代码(AndroidManifest.xml): 复制代码 代码如下: <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/><uses-permission android:name="a

查看 并发请求数及其TCP连接状态

服务器上的一些统计数据: 1)统计80端口连接数netstat -nat|grep -i "80"|wc -l 2)统计httpd协议连接数ps -ef|grep httpd|wc -l 3).统计已连接上的,状态为"establishednetstat -na|grep ESTABLISHED|wc -l 4).查出哪个IP地址连接最多,将其封了.netstat -na|grep ESTABLISHED|awk {print $5}|awk -F: {print $1}|s

Android 网络连接状态的监控

有些应用需要连接网络,例如更新后台服务,刷新数据等,最通常的做法是定期联网,直接使用网上资源.缓存数据或执行一个下载任务来更新数据. 但是如果终端设备没有连接网络,或者网速较慢,就没必要执行这些任务.可以使用ConnectivityManager检查是事联网以及当前是何种类型的网络.具体 代码如下: ConnectivityManager cm = (ConnectivityManager) getApplicationContext().getSystemService(Context.CON