网络设备的打开函数__dev_open,对应于应用层的命令,以下可见,其中会设置状态位__LINK_STATE_START,但是如果设备驱动层的ndo_open函数执行失败,将清除此状态位。否则,执行成功之后,设备将设置IFF_UP标志位。
可见两者之间差着对驱动层ndo_open函数的调用。
static int __dev_open(struct net_device *dev, struct netlink_ext_ack *extack)
{
const struct net_device_ops *ops = dev->netdev_ops;
set_bit(__LINK_STATE_START, &dev->state);
if (!ret && ops->ndo_open)
ret = ops->ndo_open(dev);
if (ret)
clear_bit(__LINK_STATE_START, &dev->state);
else {
dev->flags |= IFF_UP;
对应于命令,内核函数__dev_close_many执行时,首先清除__LINK_STATE_START状态位,意味着函数netif_running将不成立。其次,对于IFF_UP标志为,在执行驱动层的ndo_stop函数之后,清除此标志,顺序与以上__dev_open函数中相反。
static void __dev_close_many(struct list_head *head)
{
list_for_each_entry(dev, head, close_list) {
...
clear_bit(__LINK_STATE_START, &dev->state);
smp_mb__after_atomic(); /* Commit netif_running(). */
}
dev_deactivate_many(head);
list_for_each_entry(dev, head, close_list) {
const struct net_device_ops *ops = dev->netdev_ops;
if (ops->ndo_stop)
ops->ndo_stop(dev);
dev->flags &= ~IFF_UP;
以上可见,IFF_UP标志位和__LINK_STATE_START状态位都是和命令行的用户操作相关的,但是对这两者的判断使用的地方不相同。内核中为状态位__LINK_STATE_START封装了单独的函数netif_running,对于标志位IFF_UP,直接使用(dev->flags & IFF_UP)做判断。
__LINK_STATE_START状态位在于标识设备是否执行了open函数;而IFF_UP标志更进一步表示驱动层面的ndo_open函数的执行成功。
static inline bool netif_running(const struct net_device *dev)
{
return test_bit(__LINK_STATE_START, &dev->state);
}
另外,在内核中网络设备的__LINK_STATE_START状态位,和其IFF_UP标志位总是相同的,都是同时置位或者同时清除。但是如以上的__dev_close_many函数,两个位的清除操作之间由一定的时间差,所以在两个位有差别的是在两个置位或者清除之间使用的函数,其它情况下,二者无差别。
两者的用法
IFF_UP主要使用在网络协议栈,网卡驱动中很少使用,因为对于网卡的大部分操作只需要网卡初始化完成即可,而不用要求网卡一定处于UP状态(IFF_UP),即不要求一定执行了网卡驱动中的ndo_open函数。而对于协议栈,例如核心发送函数__dev_queue_xmit,当然要求设备处于UP状态,能够马上发送报文。
static int __dev_queue_xmit(struct sk_buff *skb, struct net_device *sb_dev)
{
...
if (dev->flags & IFF_UP) {
或者,在路由子系统中,函数fib_check_nh在检查下一跳地址时,判断相应出口设备的IFF_UP标志,保证下一跳的出口设备马上可用。
static int fib_check_nh(struct fib_config *cfg, struct fib_nh *nh, struct netlink_ext_ack *extack)
{
net = cfg->fc_nlinfo.nl_net;
if (nh->nh_gw) {
if (nh->nh_flags & RTNH_F_ONLINK) {
...
dev = __dev_get_by_index(net, nh->nh_oif);
if (!(dev->flags & IFF_UP)) {
NL_SET_ERR_MSG(extack, "Nexthop device is not up");
return -ENETDOWN;
而对于状态位__LINK_STATE_START,协议栈和驱动中都有使用,比如在Intel的驱动程序ixgbe中,函数ixgbe_write_mc_addr_list首先判断了状态标志__LINK_STATE_START。
static int ixgbe_write_mc_addr_list(struct net_device *netdev)
{
struct ixgbe_adapter *adapter = netdev_priv(netdev);
struct ixgbe_hw *hw = &adapter->hw;
if (!netif_running(netdev))
return 0;
if (hw->mac.ops.update_mc_addr_list)
hw->mac.ops.update_mc_addr_list(hw, netdev);
内核版本 5.0