网络设备之监测连接状态

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

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

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

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

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

相关函数的调用关系如下:

 1 /**
 2  * netif_carrier_on(off)两个函数均会调用linkwatch_fire_event
 3  * (netif_carrier_on | netif_carrier_off) 
 4  *           |------------>|--->linkwatch_fire_event
 5  *
 6  * linkwatch_fire_event
 7  *    |-->linkwatch_urgent_event
 8  *    |-->linkwatch_add_event
 9  *    |-->linkwatch_schedule_work-->linkwatch_event-->__linkwatch_run_queue
10  *                                                         |---->linkwatch_do_dev
11  */

当监测到设备传递信号时函数netif_carrier_on会被调用,并调用linkwatch_fire_event函数将设备加入到事件处理队列进行处理;

 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 }

当监测到设备信号丢失时函数netif_carrier_off会被调用,并调用linkwatch_fire_event函数将设备加入到事件处理队列进行处理;

 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 }

linkwatch_fire_event函数将设备加入到事件队列,并且进行事件调度,调度中会根据是否为紧急事件做不同处理;

 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 }

linkwatch_urgent_event判断是否是否需要紧急处理;

 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 }

linkwatch_add_event将设备加入到事件处理链表;

 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 }

linkwatch_schedule_work对事件处理进行调度,紧急事件立即执行,非紧急事件延后执行;

 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 }

__linkwatch_run_queue完成对事件调度队列中设备的处理;

 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 }

linkwatch_do_dev完成对某个设备的状态改变处理;

 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 }
原文地址:https://www.cnblogs.com/wanpengcoder/p/7529299.html