JJJ:netdev_run_todo

net/core/dev.c

由unregister_netdev->rtnl_unlock触发

c 复制代码
8986 void netdev_run_todo(void)
8987 {
8988     struct list_head list;
8989
8990     /* Snapshot list, allow later requests */
8991     list_replace_init(&net_todo_list, &list); 把net_todo_list转移到list
8992
8993     __rtnl_unlock();
8994
8995
8996     /* Wait for rcu callbacks to finish before next phase */
8997     if (!list_empty(&list))
8998         rcu_barrier();
8999
9000     while (!list_empty(&list)) { 开始遍历这个表,这个表只会有一个元素
9001         struct net_device *dev   找到列表元素对应的net_device
9002             = list_first_entry(&list, struct net_device, todo_list);
9003         list_del(&dev->todo_list);
9004
9005         if (unlikely(dev->reg_state != NETREG_UNREGISTERING)) {
9006             pr_err("network todo '%s' but state %d\n",
9007                    dev->name, dev->reg_state);
9008             dump_stack();
9009             continue;
9010         }
9011
9012         dev->reg_state = NETREG_UNREGISTERED;
9013
9014         netdev_wait_allrefs(dev);
9015
9016         /* paranoia */
9017         BUG_ON(netdev_refcnt_read(dev));
9018         BUG_ON(!list_empty(&dev->ptype_all));
9019         BUG_ON(!list_empty(&dev->ptype_specific));
9020         WARN_ON(rcu_access_pointer(dev->ip_ptr));
9021         WARN_ON(rcu_access_pointer(dev->ip6_ptr));
9022 #if IS_ENABLED(CONFIG_DECNET)
9023         WARN_ON(dev->dn_ptr);
9024 #endif
9025         if (dev->priv_destructor)
9026             dev->priv_destructor(dev);
9027         if (dev->needs_free_netdev)
9028             free_netdev(dev);
9029
9030         /* Report a network device has been unregistered */
9031         rtnl_lock();
9032         dev_net(dev)->dev_unreg_count--;
9033         __rtnl_unlock();
9034         wake_up(&netdev_unregistering_wq);
9035
9036         /* Free network device */
9037         kobject_put(&dev->dev.kobj);
9038     }
9039 }



8901 /**
8902  * netdev_wait_allrefs - wait until all references are gone.
8903  * @dev: target net_device
8904  *
8905  * This is called when unregistering network devices.
8906  *
8907  * Any protocol or device that holds a reference should register
8908  * for netdevice notification, and cleanup and put back the
8909  * reference if they receive an UNREGISTER event.
8910  * We can get stuck here if buggy protocols don't correctly
8911  * call dev_put.
8912  */
8913 static void netdev_wait_allrefs(struct net_device *dev)
8914 {
8915     unsigned long rebroadcast_time, warning_time;
8916     int refcnt;
8917
8918     linkwatch_forget_dev(dev);
8919
8920     rebroadcast_time = warning_time = jiffies;
8921     refcnt = netdev_refcnt_read(dev);   把每个cpu对该网卡的引用都加起来
8922
8923     while (refcnt != 0) {   只要引用计数不为0,就一直循环
8924         if (time_after(jiffies, rebroadcast_time + 1 * HZ)) {
8925             rtnl_lock();
8926
8927             /* Rebroadcast unregister notification */
8928             call_netdevice_notifiers(NETDEV_UNREGISTER, dev);
8929
8930             __rtnl_unlock();
8931             rcu_barrier();
8932             rtnl_lock();
8933
8934             if (test_bit(__LINK_STATE_LINKWATCH_PENDING,
8935                      &dev->state)) {
8936                 /* We must not have linkwatch events
8937                  * pending on unregister. If this
8938                  * happens, we simply run the queue
8939                  * unscheduled, resulting in a noop
8940                  * for this device.
8941                  */
8942                 linkwatch_run_queue();
8943             }
8944
8945             __rtnl_unlock();
8946
8947             rebroadcast_time = jiffies;
8948         }
8949
8950         msleep(250);
8951
8952         refcnt = netdev_refcnt_read(dev);
8953
8954         if (refcnt && time_after(jiffies, warning_time + 10 * HZ)) {
8955             pr_emerg("unregister_netdevice: waiting for %s to become free. Usage count = %d\n",
8956                  dev->name, refcnt);
8957             warning_time = jiffies;
8958         }
8959     }
8960 }






用于从全局链表中移除与指定网络设备`dev`相关的链路状态监视事件,并在移除后清理相关资源。
211 void linkwatch_forget_dev(struct net_device *dev)
212 {
213     unsigned long flags;
214     int clean = 0;
215
216     spin_lock_irqsave(&lweventlist_lock, flags); flags用于保存中断状态,并获取自旋锁
217     if (!list_empty(&dev->link_watch_list)) {  如果不是空链表,则表示该设备有待处理的链路状态监视事件。
218         list_del_init(&dev->link_watch_list);
219         clean = 1;  设置变量clean为1,表示设备的链路状态监视事件已被清理。
220     }
221     spin_unlock_irqrestore(&lweventlist_lock, flags); 恢复中断状态,释放自旋锁
222     if (clean) 检查clean变量是否为1。如果是,说明成功清理了网络设备的链路状态监视事件
223         linkwatch_do_dev(dev); 调用linkwatch_do_dev函数进一步处理设备的链路状态变化。
224 }







把每个cpu对该网卡的引用都加起来
8891 int netdev_refcnt_read(const struct net_device *dev)
8892 {
8893     int i, refcnt = 0;
8894
8895     for_each_possible_cpu(i)
8896         refcnt += *per_cpu_ptr(dev->pcpu_refcnt, i);
8897     return refcnt;
8898 }




处理网络设备的链路状态变化
144 static void linkwatch_do_dev(struct net_device *dev)
145 {
146     /*
147      * Make sure the above read is complete since it can be
148      * rewritten as soon as we clear the bit below.
149      */
150     smp_mb__before_atomic(); 确保之前对设备链路状态的读取操作完成,这里插入了一条内存屏障指令
151
152     /* We are about to handle this device,
153      * so new events can be accepted
154      */清除设备状态标志__LINK_STATE_LINKWATCH_PENDING,表示已经开始处理此设备的链路状态变化。
155     clear_bit(__LINK_STATE_LINKWATCH_PENDING, &dev->state); 
156
157     rfc2863_policy(dev); 遵循RFC 2863标准,处理网络设备的连通性状态信息。
158     if (dev->flags & IFF_UP) { 检查设备是否已启动(IFF_UP标志已设置)
159         if (netif_carrier_ok(dev)) 链路载波(carrier)可用(netif_carrier_ok返回真)
160             dev_activate(dev); 激活设备
161         else
162             dev_deactivate(dev);
163
164         netdev_state_change(dev);通知网络子系统设备的链路状态发生了变化
165     }
166     dev_put(dev);
167 }



通知网络子系统设备的链路状态发生了变化:一个是通知链通知,一个是netlink消息
1342 void netdev_state_change(struct net_device *dev)
1343 {
1344     if (dev->flags & IFF_UP) {
1345         struct netdev_notifier_change_info change_info = {
1346             .info.dev = dev,
1347         };
1348
1349         call_netdevice_notifiers_info(NETDEV_CHANGE,
1350                           &change_info.info);
1351         rtmsg_ifinfo(RTM_NEWLINK, dev, 0, GFP_KERNEL);
1352     }
1353 }




激活网络设备,使其能够正常发送和接收数据包
1114 void dev_activate(struct net_device *dev)
1115 {
1116     int need_watchdog;
1117
1118     /* No queueing discipline is attached to device;
1119      * create default one for devices, which need queueing
1120      * and noqueue_qdisc for virtual interfaces
1121      */
1122
1123     if (dev->qdisc == &noop_qdisc)
1124         attach_default_qdiscs(dev);
1125 检查网络设备的链路载波(carrier)状态是否正常。链路未就绪(netif_carrier_ok返回假),则延迟设备的激活,直到链路恢复正常。
1126     if (!netif_carrier_ok(dev)) 
1127         /* Delay activation until next carrier-on event */
1128         return;
1129
1130     need_watchdog = 0;遍历网络设备的所有发送队列,并调用transition_one_qdisc函数处理每个队列
1131     netdev_for_each_tx_queue(dev, transition_one_qdisc, &need_watchdog);
1132     if (dev_ingress_queue(dev))如果设备启用了入口(ingress)队列,也会调用transition_one_qdisc处理入口队列
1133         transition_one_qdisc(dev, dev_ingress_queue(dev), NULL);
1134
1135     if (need_watchdog) {
1136         netif_trans_update(dev);  更新开始时间戳
1137         dev_watchdog_up(dev);  开启网卡看门狗
1138     }
1139 }




更新开始时间戳
3944 /* legacy drivers only, netdev_start_xmit() sets txq->trans_start */
3945 static inline void netif_trans_update(struct net_device *dev)
3946 {
3947     struct netdev_queue *txq = netdev_get_tx_queue(dev, 0);
3948
3949     if (txq->trans_start != jiffies)
3950         txq->trans_start = jiffies;
3951 }







 492 static void dev_watchdog_up(struct net_device *dev)
 493 {
 494     __netdev_watchdog_up(dev);
 495 }


开启定时器,定时器处理函数见https://blog.csdn.net/engineer0/article/details/137529237
处理函数主要是看发送率是否有超时
 480 void __netdev_watchdog_up(struct net_device *dev)
 481 {
 482     if (dev->netdev_ops->ndo_tx_timeout) {
 483         if (dev->watchdog_timeo <= 0)
 484             dev->watchdog_timeo = 5*HZ;
 485         if (!mod_timer(&dev->watchdog_timer,
 486                    round_jiffies(jiffies + dev->watchdog_timeo)))
 487             dev_hold(dev);
 488     }
 489 }



见https://blog.csdn.net/engineer0/article/details/137529237
1266 void dev_deactivate(struct net_device *dev)
1267 {
1268     LIST_HEAD(single);
1269
1270     list_add(&dev->close_list, &single);
1271     dev_deactivate_many(&single);
1272     list_del(&single);
1273 }
相关推荐
PcVue China2 小时前
PcVue + SQL Grid : 释放数据的无限潜力
大数据·服务器·数据库·sql·科技·安全·oracle
长安11082 小时前
前后端、网关、协议方面补充
网络
舞动CPU4 小时前
linux c/c++最高效的计时方法
linux·运维·服务器
钰@5 小时前
小程序开发者工具的network选项卡中有某域名的接口请求,但是在charles中抓不到该接口
运维·服务器·小程序
wanhengwangluo5 小时前
云服务器和物理服务器的区别有哪些?
运维·服务器
hzyyyyyyyu5 小时前
隧道技术-tcp封装icmp出网
网络·网络协议·tcp/ip
南猿北者6 小时前
docker Network(网络)
网络·docker·容器
Hacker_Nightrain7 小时前
网络安全CTF比赛规则
网络·安全·web安全
扣得君7 小时前
C++20 Coroutine Echo Server
运维·服务器·c++20
网络安全指导员8 小时前
恶意PDF文档分析记录
网络·安全·web安全·pdf