zoukankan      html  css  js  c++  java
  • 网络设备之监测连接状态

    通常网络设备会定时地检测设备是否处于可传递状态。当状态发生变化时,会调用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 }
  • 相关阅读:
    LeetCode-102-二叉树的层序遍历
    LeetCode-086-分隔链表
    LeetCode-082-删除排序链表中的重复元素 II
    LeetCode-081-搜索旋转排序数组 II
    [leetcode]92. Reverse Linked List II反转链表2
    [leetcode]94. Binary Tree Inorder Traversal二叉树中序遍历
    [leetcode]100. Same Tree相同的树
    [leetcode]54. Spiral Matrix螺旋矩阵
    [leetcode]58. Length of Last Word最后一个词的长度
    [leetcode]41. First Missing Positive第一个未出现的正数
  • 原文地址:https://www.cnblogs.com/wanpengcoder/p/7529299.html
Copyright © 2011-2022 走看看