网络设备之监测连接状态
通常网络设备会定时地检测设备是否处于可传递状态。当状态发生变化时,会调用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 }