1. 程式人生 > >網絡設備之偵測連接狀態

網絡設備之偵測連接狀態

and wrap 網線 sign this make 丟失 int new

通常,網絡設備會定時地偵測設備是否處於可傳遞狀態。當狀態發生變化時,會調用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 }

網絡設備之偵測連接狀態