JJJ:netdev_run_todo

net/core/dev.c

由unregister_netdev->rtnl_unlock触发

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.youkuaiyun.com/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.youkuaiyun.com/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 }

<think>好的,我现在需要帮助用户解决IPv6 ADDRCONF NETDEV_UP eth_1_1_4 link not ready的问题。用户提到网络接口eth_1_1_4未准备好,导致出现这个错误。首先,我得回忆一下之前的回答和用户提供的引用内容,看看有没有相关的信息可以借鉴。 用户之前询问了如何查看防火墙日志来分析IPv6流量问题,我给出了详细的步骤,包括确定防火墙类型、启用日志、实时监控、分析日志特征等。现在的问题不同,是关于网络接口未准备好,可能与硬件、驱动或配置有关。用户提供的引用中提到了类似的问题,比如网卡不稳定、重复link up/down,以及解决方法,比如检查网线、驱动、配置等。 首先,我需要明确ADDRCONF(NETDEV_UP)这个错误的具体含义。根据引用内容,这通常发生在网络接口被启用但物理链路未准备好时。可能的原因包括物理连接问题、网卡或驱动故障、配置错误、自动协商问题、固件或内核问题,以及IPv6相关配置问题。 接下来,我需要按照步骤来排查问题。先从物理层开始,检查网线、接口状态,然后检查驱动和内核模块,确认网卡是否被正确识别。接着查看网络配置,特别是IPv6的设置,是否有冲突或错误配置。然后检查自动协商和双工模式,是否设置正确。如果问题依旧,可能需要更新驱动或固件,或者检查内核日志中的详细错误信息。 用户提供的引用中,引用[2]提到修改网卡IP和网关的方法,引用[3]和[4]提到驱动和配置的问题,引用[5]涉及启动时的错误。这些都可能与当前问题相关,比如驱动不兼容、配置错误等。 另外,用户提到的接口名称是eth_1_1_4,这可能是一个自定义的接口名,需要确认是否配置正确。检查网络管理工具如NetworkManager是否干扰了接口配置,或者是否有udev规则导致接口重命名。 在解决方案中,我需要分步骤指导用户检查物理连接、驱动状态、网络配置、自动协商等,并提供具体的命令示例,如ethtool、dmesg、ip link等。同时,可能需要建议用户禁用IPv6测试,或者调整MTU值,排除这些因素。 最后,要确保回答结构清晰,步骤明确,帮助用户逐步排查问题,并引用之前的参考内容作为支持。同时,生成的相关问题需要与当前主题相关,比如如何禁用IPv6、检查驱动兼容性、分析内核日志等。</think>--- ### **IPv6 ADDRCONF(NETDEV_UP) eth_1_1_4链路未就绪问题排查指南** --- #### **1. 问题本质分析** `ADDRCONF(NETDEV_UP): eth_1_1_4: link is not ready`表示系统尝试启用网络接口时,**物理链路未完成协商**(如网线未插好、交换机端口故障或驱动异常)。该报错与IPv6地址自动配置(SLAAC/DHCPv6)直接相关[^1][^3]。 --- #### **2. 分层排查流程** ##### **2.1 物理层检查** - **网线/端口验证** ```bash # 检查接口物理连接状态(关注"Link detected"字段) ethtool eth_1_1_4 | grep "Link detected" ``` 若输出`no`,需依次排查: 1. 更换网线或尝试其他交换机端口 2. 检查RJ45接口针脚是否氧化变形 3. 使用`phy-handle`定位PHY芯片状态(常见于嵌入式设备)[^3]: ```bash dmesg | grep -i "phy.*eth_1_1_4" ``` - **PHY芯片诊断** 针对LAN8720A等PHY芯片(引用[1]),检查供电和时钟信号: ```bash # 查看PHY寄存器状态(需root权限) mii-tool -v eth_1_1_4 ``` **关键寄存器值**: - **Basic Mode Status Register (0x01)**:确认`Link status`是否为1 - **PHY Identifier (0x02-0x03)**:验证芯片型号是否匹配[^1] --- ##### **2.2 驱动与内核模块** - **驱动兼容性验证** ```bash # 查看驱动加载状态 lsmod | grep -E 'fec|higmac|gmac' # 检查内核版本与驱动匹配性(常见于Zynq平台[^5]) uname -a ``` **典型问题**: - 旧版内核未适配特定PHY芯片(如LAN8720A需启用`smsc95xx`驱动) - 设备树中PHY地址配置错误(引用[3]中`phy_addr=1`需与实际一致) - **强制重置网络接口** ```bash # 卸载并重新加载驱动模块 sudo rmmod fec sudo modprobe fec ip link set eth_1_1_4 up ``` --- ##### **2.3 网络配置检查** - **IPv6自动配置冲突** ```bash # 查看NetworkManager状态(若存在) systemctl status NetworkManager # 禁用IPv6临时测试 sysctl -w net.ipv6.conf.eth_1_1_4.disable_ipv6=1 ``` 若禁用IPv6后链路恢复,需检查: 1. `/etc/sysconfig/network-scripts/ifcfg-eth_1_1_4`中`IPV6INIT`参数 2. DHCPv6服务是否异常发送错误配置[^2] - **MTU与双工模式强制设置** ```bash # 强制设置为100M全双工(适配老旧设备) ethtool -s eth_1_1_4 speed 100 duplex full autoneg off # 调整MTU值(避免分片问题) ip link set dev eth_1_1_4 mtu 1492 ``` --- ##### **2.4 内核日志深度分析** - **时序关联性排查** ```bash # 过滤与eth_1_1_4相关的内核事件 dmesg | grep -i "eth_1_1_4" | less # 典型错误模式: # 1. "libphy: ... reset timed out" → PHY芯片通信故障 # 2. "higmac: ... rx error" → DMA缓冲区配置错误[^3] ``` --- #### **3. 嵌入式系统专项排查(针对Zynq/正点原子平台[^5])** - **设备树配置验证** 检查`pl.dtsi`或`system-user.dtsi`中: ```dts &gem0 { phy-handle = <&phy0>; phy-mode = "rgmii-id"; status = "okay"; phy0: phy@1 { compatible = "ethernet-phy-id001C.C916"; // LAN8720A PHY ID reg = <1>; // 必须与实际PHY地址一致 }; }; ``` - **U-Boot环境变量检查** ```bash # 在U-Boot中执行 printenv ethaddr eth1addr ``` 确认MAC地址未重复或全零(某些PHY芯片需唯一MAC地址) --- #### **4. 解决方案总结** | 故障类型 | 解决措施 | 验证命令 | |------------------------|---------------------------------------|-----------------------------------| | **PHY通信故障** | 检查设备树PHY地址/更换芯片 | `mii-tool -vvv eth_1_1_4` | | **驱动不兼容** | 升级内核或回退稳定版本 | `modinfo fec` | | **自动协商失败** | 强制设置速度/双工模式 | `ethtool eth_1_1_4` | | **IPv6配置冲突** | 禁用IPv6或修复SLAAC配置 | `sysctl net.ipv6.conf.eth_1_1_4` | | **硬件信号不稳定** | 检查电源纹波/添加磁珠滤波 | 示波器测量MDIO/MDC信号 | --- ### **扩展测试方法** - **硬件环回测试** 短接网口TX+/-与RX+/-,发送测试包: ```bash ping6 -I eth_1_1_4 ff02::1%eth_1_1_4 ``` - **PHY寄存器手动读写** ```bash # 读取PHY寄存器0x1F(扩展页寄存器) ethtool --phy-regs eth_1_1_4 0x1F ``` --- ### **相关问题** 1. 如何通过`ethtool`诊断RGMII接口的时序问题? 2. 嵌入式Linux系统中如何正确配置设备树中的PHY节点? 3. 网络接口频繁UP/DOWN时,如何捕获MDIO总线上的通信数据? 4. 如何通过`sysfs`接口动态修改网络驱动参数?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值