网络设备的__LINK_STATE_START状态与IFF_UP标志

网络设备的打开函数__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

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页