通常网络设备会定时地检测设备是否处于可传递状态。当状态发生变化时,会调用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 /* 设备状态改变处理,执行netdev_chain上设备状态变更回调 */
30 netdev_state_change(dev);
31 }
32 dev_put(dev);
33 }