启用设备,最终会调用__dev_open函数,对设备进行启用,进行一些必要初始化和通知,调用关系如下,主要对这几个函数进行分析;
dev_change_flags---->_dev_change_flags---->__dev_open
dev_open---->__dev_open
__dev_open
|---->dev_set_rx_mode
|---->__dev_set_promiscuity
1 int __dev_change_flags(struct net_device *dev, unsigned int flags) 2 { 3 unsigned int old_flags = dev->flags; 4 int ret; 5 6 ASSERT_RTNL(); 7 8 /* 9 * Set the flags on our device. 10 */ 11 12 dev->flags = (flags & (IFF_DEBUG | IFF_NOTRAILERS | IFF_NOARP | 13 IFF_DYNAMIC | IFF_MULTICAST | IFF_PORTSEL | 14 IFF_AUTOMEDIA)) | 15 (dev->flags & (IFF_UP | IFF_VOLATILE | IFF_PROMISC | 16 IFF_ALLMULTI)); 17 18 /* 19 * Load in the correct multicast list now the flags have changed. 20 */ 21 22 if ((old_flags ^ flags) & IFF_MULTICAST) 23 dev_change_rx_flags(dev, IFF_MULTICAST); 24 25 dev_set_rx_mode(dev); 26 27 /* 28 * Have we downed the interface. We handle IFF_UP ourselves 29 * according to user attempts to set it, rather than blindly 30 * setting it. 31 */ 32 33 ret = 0; 34 /* 两个标识有一个是IFF_UP */ 35 if ((old_flags ^ flags) & IFF_UP) 36 /* 源标识有IFF_UP则调用关闭,否则调用开启 */ 37 ret = ((old_flags & IFF_UP) ? __dev_close : __dev_open)(dev); 38 39 if ((flags ^ dev->gflags) & IFF_PROMISC) { 40 int inc = (flags & IFF_PROMISC) ? 1 : -1; 41 unsigned int old_flags = dev->flags; 42 43 dev->gflags ^= IFF_PROMISC; 44 45 if (__dev_set_promiscuity(dev, inc, false) >= 0) 46 if (dev->flags != old_flags) 47 dev_set_rx_mode(dev); 48 } 49 50 /* NOTE: order of synchronization of IFF_PROMISC and IFF_ALLMULTI 51 * is important. Some (broken) drivers set IFF_PROMISC, when 52 * IFF_ALLMULTI is requested not asking us and not reporting. 53 */ 54 if ((flags ^ dev->gflags) & IFF_ALLMULTI) { 55 int inc = (flags & IFF_ALLMULTI) ? 1 : -1; 56 57 dev->gflags ^= IFF_ALLMULTI; 58 __dev_set_allmulti(dev, inc, false); 59 } 60 61 return ret; 62 }
1 /** 2 * dev_open - prepare an interface for use. 3 * @dev: device to open 4 * 5 * Takes a device from down to up state. The device's private open 6 * function is invoked and then the multicast lists are loaded. Finally 7 * the device is moved into the up state and a %NETDEV_UP message is 8 * sent to the netdev notifier chain. 9 * 10 * Calling this function on an active interface is a nop. On a failure 11 * a negative errno code is returned. 12 */ 13 int dev_open(struct net_device *dev) 14 { 15 int ret; 16 17 /* 如果已经打开返回 */ 18 if (dev->flags & IFF_UP) 19 return 0; 20 21 /* 打开设备 */ 22 ret = __dev_open(dev); 23 if (ret < 0) 24 return ret; 25 26 /* 通知设备打开 */ 27 rtmsg_ifinfo(RTM_NEWLINK, dev, IFF_UP|IFF_RUNNING, GFP_KERNEL); 28 call_netdevice_notifiers(NETDEV_UP, dev); 29 30 return ret; 31 }
1 static int __dev_open(struct net_device *dev) 2 { 3 const struct net_device_ops *ops = dev->netdev_ops; 4 int ret; 5 6 ASSERT_RTNL(); 7 8 /* 设备不可用 */ 9 if (!netif_device_present(dev)) 10 return -ENODEV; 11 12 /* Block netpoll from trying to do any rx path servicing. 13 * If we don't do this there is a chance ndo_poll_controller 14 * or ndo_poll may be running while we open the device 15 */ 16 /* 禁用netpoll */ 17 netpoll_poll_disable(dev); 18 19 /* 设备打开前通知 */ 20 ret = call_netdevice_notifiers(NETDEV_PRE_UP, dev); 21 ret = notifier_to_errno(ret); 22 if (ret) 23 return ret; 24 25 /* 设置设备打开标记 */ 26 set_bit(__LINK_STATE_START, &dev->state); 27 28 /* 校验地址 */ 29 if (ops->ndo_validate_addr) 30 ret = ops->ndo_validate_addr(dev); 31 32 /* 执行打开 */ 33 if (!ret && ops->ndo_open) 34 ret = ops->ndo_open(dev); 35 36 /* 启用netpoll */ 37 netpoll_poll_enable(dev); 38 39 /* 失败,清除打开标记 */ 40 if (ret) 41 clear_bit(__LINK_STATE_START, &dev->state); 42 43 /* 设备打开操作 */ 44 else { 45 /* 设置打开标记 */ 46 dev->flags |= IFF_UP; 47 48 /* 设置接收模式 */ 49 dev_set_rx_mode(dev); 50 /* 初始化排队规则 */ 51 dev_activate(dev); 52 /* 加入设备数据到熵池 */ 53 add_device_randomness(dev->dev_addr, dev->addr_len); 54 } 55 56 return ret; 57 }
1 /* 2 * Upload unicast and multicast address lists to device and 3 * configure RX filtering. When the device doesn't support unicast 4 * filtering it is put in promiscuous mode while unicast addresses 5 * are present. 6 */ 7 void __dev_set_rx_mode(struct net_device *dev) 8 { 9 const struct net_device_ops *ops = dev->netdev_ops; 10 11 /* dev_open will call this function so the list will stay sane. */ 12 /* 设备未启动 */ 13 if (!(dev->flags&IFF_UP)) 14 return; 15 16 /* 设备不存在 */ 17 if (!netif_device_present(dev)) 18 return; 19 20 /* 不支持单播过滤 */ 21 /* 未实现ndo_set_rx_mode */ 22 if (!(dev->priv_flags & IFF_UNICAST_FLT)) { 23 /* Unicast addresses changes may only happen under the rtnl, 24 * therefore calling __dev_set_promiscuity here is safe. 25 */ 26 /* 单播硬件地址存在&& 单播混杂模式未开启 */ 27 if (!netdev_uc_empty(dev) && !dev->uc_promisc) { 28 /* 开启混杂模式 */ 29 __dev_set_promiscuity(dev, 1, false); 30 dev->uc_promisc = true; 31 } 32 /* 单播硬件地址不存在&& 设备开启混杂模式 */ 33 else if (netdev_uc_empty(dev) && dev->uc_promisc) { 34 /* */ 35 __dev_set_promiscuity(dev, -1, false); 36 dev->uc_promisc = false; 37 } 38 } 39 40 /* 调用设备设置接收模式函数 */ 41 if (ops->ndo_set_rx_mode) 42 ops->ndo_set_rx_mode(dev); 43 }
1 /* 设置混杂模式 */ 2 static int __dev_set_promiscuity(struct net_device *dev, int inc, bool notify) 3 { 4 unsigned int old_flags = dev->flags; 5 kuid_t uid; 6 kgid_t gid; 7 8 ASSERT_RTNL(); 9 10 /* 打混杂标记 */ 11 dev->flags |= IFF_PROMISC; 12 13 /* 改变混杂计数,inc可能为负 */ 14 dev->promiscuity += inc; 15 16 /* 所有混杂均释放 */ 17 if (dev->promiscuity == 0) { 18 /* 19 * Avoid overflow. 20 * If inc causes overflow, untouch promisc and return error. 21 */ 22 /* 当前是释放混杂计数操作,则关闭混杂模式 */ 23 if (inc < 0) 24 dev->flags &= ~IFF_PROMISC; 25 /* 否则出错 */ 26 else { 27 dev->promiscuity -= inc; 28 pr_warn("%s: promiscuity touches roof, set promiscuity failed. promiscuity feature of device might be broken.\n", 29 dev->name); 30 return -EOVERFLOW; 31 } 32 } 33 34 /* 新旧标识不相同 */ 35 if (dev->flags != old_flags) { 36 pr_info("device %s %s promiscuous mode\n", 37 dev->name, 38 dev->flags & IFF_PROMISC ? "entered" : "left"); 39 if (audit_enabled) { 40 current_uid_gid(&uid, &gid); 41 audit_log(current->audit_context, GFP_ATOMIC, 42 AUDIT_ANOM_PROMISCUOUS, 43 "dev=%s prom=%d old_prom=%d auid=%u uid=%u gid=%u ses=%u", 44 dev->name, (dev->flags & IFF_PROMISC), 45 (old_flags & IFF_PROMISC), 46 from_kuid(&init_user_ns, audit_get_loginuid(current)), 47 from_kuid(&init_user_ns, uid), 48 from_kgid(&init_user_ns, gid), 49 audit_get_sessionid(current)); 50 } 51 52 /* 调用改变rx标识操作 */ 53 dev_change_rx_flags(dev, IFF_PROMISC); 54 } 55 56 /* 混杂模式通知 */ 57 if (notify) 58 __dev_notify_flags(dev, old_flags, IFF_PROMISC); 59 return 0;