您的位置:首页 > 理论基础 > 计算机网络

网络设备之侦测连接状态

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 - 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);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: