网口状态标志位解析part2: 内核如何维护网卡carrier的状态

内核如何维护网卡设备的RUNNING 状态

流程概述

主要几个部分:

  1. 网卡驱动有个看门狗:不同网卡驱动实现可能不太一样 ,功能负责监控网卡硬件上网线的状态, 当网线状态变换的时候,会激发内核的 carrier 处理函数。
  2. 内核两个通用的处理函数:netif_carrier_onnetif_carrier_off。这个函数会
    • 设置或者清除netdev->state上的__LINK_STATE_NOCARRIER标志位。
    • 发送事件消息给linkwatch,做后续处理.
    • 如果是网线插好了状态, 会启动一个通用的看门狗,这个看门狗是负责检测tx队列是否’HUNG’了, 如果’HUNG’了就调用网卡对应的处理函数ndo_tx_timeout, 做一些应急补救,比如对网卡队列复位等操作。这里的看门狗跟网卡驱动里的看门狗还不是同一个看门狗。具体差别待研究。
  3. linkwath模块:linkwatch本身是个workqueue 队列,对接受到的消息按照,分为紧急和非紧急两类。紧急的决定立即处理,非紧急的则挂到一个链表里,等定时器超时后,再集中处理。所有事件处理,最终都交给linkwatch_do_dev(struct net_device *dev)函数进行处理。 该函数更新netdev->operate标志位。同时调用通用的dev_activate或者dev_deactivate对网卡做网卡队列进行处理。 我们这里重点关注跟网卡状态位有管的部分,忽略跟网卡队列的处理。
    这里有两个重要函数rfc2863_policydefault_operstate 后面我们重点介绍。

carrier on 和 off 函数

netif_carrier_onnetif_carrier_off: 内核里的两个通用的处理函数,功能基本对称

carrier on详解
`netif_carrier_on`主要依次做下面三个操作
+ `__LINK_STATE_NOCARRIER`: 设置`netdev->state`上的`__LINK_STATE_NOCARRIER`标志位。这个标志位很关键,后续判断carrier 是否 OK,就看这个标志位。
如果是从无到有这个标志位,则执行下面两步,否则就跳过。
+ 增加网卡设备下的`dev->carrier_up_count`的计数次数。
+ 发送事件消息给linkwatch:让他做后续处理。激发动作有两部分
    + '__LINK_STATE_LINKWATCH_PENDING':设置这个标志位
+ 如果是网线插好了状态, 会启动一个网卡的看门狗,这个看门狗是负责检测tx队列是否'HUNG'了, 如果'HUNG'了就调用网卡对应的处理函数`ndo_tx_timeout`, 做一些应急补救,比如对网卡队列复位等操作。
1
2
3
4
4390 static inline bool netif_carrier_ok(const struct net_device *dev)
4391 {
4392 return !test_bit(__LINK_STATE_NOCARRIER, &dev->state);
4393 }
1
2
3
4
5
6
7
8
9
10
11
12
581 void netif_carrier_on(struct net_device *dev)
582 {
583 if (test_and_clear_bit(__LINK_STATE_NOCARRIER, &dev->state)) {
584 if (dev->reg_state == NETREG_UNINITIALIZED)
585 return;
586 atomic_inc(&dev->carrier_up_count);
587 linkwatch_fire_event(dev);
588 if (netif_running(dev))
589 netdev_watchdog_up(dev);
590 }
591 }
592 EXPORT_SYMBOL(netif_carrier_on);
1
2
3
4
5
6
7
8
9
10
600 void netif_carrier_off(struct net_device *dev)
601 {
602 if (!test_and_set_bit(__LINK_STATE_NOCARRIER, &dev->state)) {
603 if (dev->reg_state == NETREG_UNINITIALIZED)
604 return;
605 atomic_inc(&dev->carrier_down_count);
606 linkwatch_fire_event(dev);
607 }
608 }
609 EXPORT_SYMBOL(netif_carrier_off);

入口函数

1
2
3
4
5
6
7
8
9
10
11
291 void linkwatch_fire_event(struct net_device *dev)
292 {
293 bool urgent = linkwatch_urgent_event(dev);
294
295 if (!test_and_set_bit(__LINK_STATE_LINKWATCH_PENDING, &dev->state)) {
296 linkwatch_add_event(dev);
297 } else if (!urgent)
298 return;
299
300 linkwatch_schedule_work(urgent);
301 }

将 netdev 增加到链表中

1
2
3
4
5
6
7
8
9
10
11
124 static void linkwatch_add_event(struct net_device *dev)
125 {
126 unsigned long flags;
127
128 spin_lock_irqsave(&lweventlist_lock, flags);
129 if (list_empty(&dev->link_watch_list)) {
130 list_add_tail(&dev->link_watch_list, &lweventlist);
131 netdev_hold(dev, &dev->linkwatch_dev_tracker, GFP_ATOMIC);
132 }
133 spin_unlock_irqrestore(&lweventlist_lock, flags);
134 }

workqueue 的处理函数,dev从链表上摘下来,逐个调用linkwatch_do_dev处理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
194 static void __linkwatch_run_queue(int urgent_only)
195 {
...
224 spin_lock_irq(&lweventlist_lock);
225 list_splice_init(&lweventlist, &wrk);
226
227 while (!list_empty(&wrk) && do_dev > 0) {
229
230 dev = list_first_entry(&wrk, struct net_device, link_watch_list);
...
243 linkwatch_do_dev(dev);
...
246 }
...
254 }

link watch

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
166 static void linkwatch_do_dev(struct net_device *dev)
167 {
...
177 clear_bit(__LINK_STATE_LINKWATCH_PENDING, &dev->state);
178
179 rfc2863_policy(dev);
180 if (dev->flags & IFF_UP) {
181 if (netif_carrier_ok(dev))
182 dev_activate(dev);
183 else
184 dev_deactivate(dev);
185
186 netdev_state_change(dev);
187 }
...
192 }
两个状态维护函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
74 static void rfc2863_policy(struct net_device *dev)
75 {
76 unsigned int operstate = default_operstate(dev);
77
78 if (operstate == READ_ONCE(dev->operstate))
79 return;
80
81 switch(dev->link_mode) {
82 case IF_LINK_MODE_TESTING:
83 if (operstate == IF_OPER_UP)
84 operstate = IF_OPER_TESTING;
85 break;
86
87 case IF_LINK_MODE_DORMANT:
88 if (operstate == IF_OPER_UP)
89 operstate = IF_OPER_DORMANT;
90 break;
91 case IF_LINK_MODE_DEFAULT:
92 default:
93 break;
94 }
95
96 WRITE_ONCE(dev->operstate, operstate);
97 }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
36 static unsigned int default_operstate(const struct net_device *dev)
37 {
38 if (netif_testing(dev))
39 return IF_OPER_TESTING;
40
41 /* Some uppers (DSA) have additional sources for being down, so
42 * first check whether lower is indeed the source of its down state.
43 */
44 if (!netif_carrier_ok(dev)) {
45 struct net_device *peer;
46 int iflink;
47
48 /* If called from netdev_run_todo()/linkwatch_sync_dev(),
49 * dev_net(dev) can be already freed, and RTNL is not held.
50 */
51 if (dev->reg_state <= NETREG_REGISTERED)
52 iflink = dev_get_iflink(dev);
53 else
54 iflink = dev->ifindex;
55
56 if (iflink == dev->ifindex)
57 return IF_OPER_DOWN;
58
59 ASSERT_RTNL();
60 peer = __dev_get_by_index(dev_net(dev), iflink);
61 if (!peer)
62 return IF_OPER_DOWN;
63
64 return netif_carrier_ok(peer) ? IF_OPER_DOWN :
65 IF_OPER_LOWERLAYERDOWN;
66 }
67
68 if (netif_dormant(dev))
69 return IF_OPER_DORMANT;
70
71 return IF_OPER_UP;
72 }

回调函数 (待细看)

这部分代码要涉及到 netdev的callback链和 rtnetlin 消息通知。
是网卡设备状态变换后的消息通知和处理工作。

1
2
3
4
5
6
7
8
9
10
11
12
13
1530 void netdev_state_change(struct net_device *dev)
1531 {
1532 if (dev->flags & IFF_UP) {
1533 struct netdev_notifier_change_info change_info = {
1534 .info.dev = dev,
1535 };
1536
1537 call_netdevice_notifiers_info(NETDEV_CHANGE,
1538 &change_info.info);
1539 rtmsg_ifinfo(RTM_NEWLINK, dev, 0, GFP_KERNEL, 0, NULL);
1540 }
1541 }
1542 EXPORT_SYMBOL(netdev_state_change);