网络设备之侦测连接状态
2017-09-16 00:43
267 查看
通常,网络设备会定时地侦测设备是否处于可传递状态。当状态发生变化时,会调用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
从网上设备插拔网线或者另一端的设备关闭或禁止,都会导致连接状态改变;
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
/** * netif_carrier_on - set carrier * @dev: network device * * Device has detected that carrier. */ /* 侦测到设备传递信号时调用 */ void netif_carrier_on(struct net_device *dev) { /* 清除nocarrier标记 */ if (test_and_clear_bit(__LINK_STATE_NOCARRIER, &dev->state)) { /* 设备尚未注册,则返回 */ if (dev->reg_state == NETREG_UNINITIALIZED) return; /* 增加状态改变次数 */ atomic_inc(&dev->carrier_changes); /* 加入事件处理队列进行处理 */ linkwatch_fire_event(dev); /* 若设备正在运行 */ if (netif_running(dev)) /* 启动软件狗 */ __netdev_watchdog_up(dev); } }
/** * netif_carrier_off - clear carrier * @dev: network device * * Device has detected loss of carrier. */ /* 侦测到设备丢失信号时调用 */ void netif_carrier_off(struct net_device *dev) { /* 设置nocarrier状态 */ if (!test_and_set_bit(__LINK_STATE_NOCARRIER, &dev->state)) { /* 设备尚未注册,则返回 */ if (dev->reg_state == NETREG_UNINITIALIZED) return; /* 增加设备改变状态 */ atomic_inc(&dev->carrier_changes); /* 加入事件处理队列进行处理 */ linkwatch_fire_event(dev); } }
/* 加入事件队列处理 */ void linkwatch_fire_event(struct net_device *dev) { /* 判断是否是紧急处理的事件 */ bool urgent = linkwatch_urgent_event(dev); /* 设置待处理事件标记 */ if (!test_and_set_bit(__LINK_STATE_LINKWATCH_PENDING, &dev->state)) { /* 添加事件到事件列表 */ linkwatch_add_event(dev); } /* 设备以前已经设置了pending标记,不是紧急事件,直接返回 */ else if (!urgent) return; /* 事件调度 */ linkwatch_schedule_work(urgent); }
/* 是否需要紧急处理的事件 */ static bool linkwatch_urgent_event(struct net_device *dev) { /* 设备未运行,非紧急 */ if (!netif_running(dev)) return false; /* 设备的索引号与连接索引号不等,紧急 */ if (dev->ifindex != dev_get_iflink(dev)) return true; /* 设备作为team port,紧急 */ if (dev->priv_flags & IFF_TEAM_PORT) return true; /* 连接与否 && 发送队列排队规则改变与否 */ return netif_carrier_ok(dev) && qdisc_tx_changing(dev); }
/* 添加事件 */ static void linkwatch_add_event(struct net_device *dev) { unsigned long flags; spin_lock_irqsave(&lweventlist_lock, flags); /* 若未添加,则添加设备到事件列表 */ if (list_empty(&dev->link_watch_list)) { list_add_tail(&dev->link_watch_list, &lweventlist); dev_hold(dev); } spin_unlock_irqrestore(&lweventlist_lock, flags); }
/* 调度事件处理工作队列 */ static void linkwatch_schedule_work(int urgent) { unsigned long delay = linkwatch_nextevent - jiffies; /* 已经设置了紧急标记,则返回 */ if (test_bit(LW_URGENT, &linkwatch_flags)) return; /* Minimise down-time: drop delay for up event. */ /* 需要紧急调度 */ if (urgent) { /* 之前设置了,则返回 */ if (test_and_set_bit(LW_URGENT, &linkwatch_flags)) return; /* 未设置紧急,则立即执行 */ delay = 0; } /* If we wrap around we'll delay it by at most HZ. */ /* 如果大于1s则立即执行 */ if (delay > HZ) delay = 0; /* * If urgent, schedule immediate execution; otherwise, don't * override the existing timer. */ /* 如果设置了紧急标记,则立即执行 */ if (test_bit(LW_URGENT, &linkwatch_flags)) mod_delayed_work(system_wq, &linkwatch_work, 0); /* 未设置紧急标记,则按照delay执行 */ else schedule_delayed_work(&linkwatch_work, delay); }
/* @urgent_only--1-未到达下一次调度时间 0-已到达下次调度时间 */ static void __linkwatch_run_queue(int urgent_only) { struct net_device *dev; LIST_HEAD(wrk); /* * Limit the number of linkwatch events to one * per second so that a runaway driver does not * cause a storm of messages on the netlink * socket. This limit does not apply to up events * while the device qdisc is down. */ /* 已达到调度时间 */ if (!urgent_only) linkwatch_nextevent = jiffies + HZ; /* Limit wrap-around effect on delay. */ /* 未到达调度时间,并且下一次调度在当前时间的1s以后 那么设置调度时间是当前时间 */ else if (time_after(linkwatch_nextevent, jiffies + HZ)) linkwatch_nextevent = jiffies; /* 清除紧急标识 */ clear_bit(LW_URGENT, &linkwatch_flags); spin_lock_irq(&lweventlist_lock); list_splice_init(&lweventlist, &wrk); /* 遍历链表 */ while (!list_empty(&wrk)) { /* 获取设备 */ dev = list_first_entry(&wrk, struct net_device, link_watch_list); /* 从链表移除设备 */ list_del_init(&dev->link_watch_list); /* 未到达调度时间 && 不需要紧急处理 */ if (urgent_only && !linkwatch_urgent_event(dev)) { /* 添加到链表尾部 */ list_add_tail(&dev->link_watch_list, &lweventlist); /* 继续处理 */ continue; } spin_unlock_irq(&lweventlist_lock); /* 处理设备 */ linkwatch_do_dev(dev); spin_lock_irq(&lweventlist_lock); } /* 链表有未处理事件,则以非紧急状态调度队列 */ if (!list_empty(&lweventlist)) linkwatch_schedule_work(0); spin_unlock_irq(&lweventlist_lock); }
/* 处理某个设备的状态改变 */ static void linkwatch_do_dev(struct net_device *dev) { /* * Make sure the above read is complete since it can be * rewritten as soon as we clear the bit below. */ smp_mb__before_atomic(); /* We are about to handle this device, * so new events can be accepted */ /* 清除pending标记 */ clear_bit(__LINK_STATE_LINKWATCH_PENDING, &dev->state); rfc2863_policy(dev); /* 如果设备启动状态 */ if (dev->flags & IFF_UP) { /* 链路连接 */ if (netif_carrier_ok(dev)) /* 启用排队规则 */ dev_activate(dev); /* 否则*/ else /* 关闭排队规则 */ dev_deactivate(dev); /* 设备状态改变处理 */ netdev_state_change(dev); } dev_put(dev); }
相关文章推荐
- Android判断设备网络连接状态及判断连接方式的方法
- Android判断设备网络连接状态,并判断连接方式
- android设备判断网络连接状态
- Android判断设备网络连接状态,并判断连接方式
- Android之判断设备网络连接状态,并判断连接方式
- Android判断设备网络连接状态,并判断连接方式
- Android之判断设备网络连接状态,并判断连接方式
- Android之判断设备网络连接状态,并判断连接方式
- 判断设备和判断网络连接状态的方法
- cocos2dx实现获得设备的网络连接状态
- 检测Android设备有线网络连接状态
- Android判断设备网络连接状态,并判断连接方式
- cocos2dx实现获得设备的网络连接状态
- Android判断设备网络连接状态,并判断连接方式
- IOS 判断设备 与 判断网络连接状态
- Android判断设备网络连接状态,并判断连接方式
- Android开发中网络连接状态的判断(判断android设备是否有网络)
- 判断Android设备是否连接网络
- Android学习之 监听网络连接状态的改变
- 【转】Linux服务器上11种网络连接状态 和 TCP三次握手/四次挥手详解