net_device的打开与关闭

本文详细介绍了在Linux环境下,如何通过`ip link`命令来打开和关闭net_device。当执行`ip link set dev {DEVICE} up`,会调用dev_open()进行设备打开,而`ip link set dev DEVICE down`则触发dev_close()进行关闭。关键点包括使用IFF_UP或__LINK_STATE_START标志判断设备状态,以及在打开关闭过程中涉及的事件通知和流量控制机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


前面的笔记分析了net_device的分配和注册流程,在可以进行数据收发之前,还需要打开net_device。对应的net_device不再工作时需要关闭net_device,这篇笔记来分析下这两个流程是如何实现的。

打开net_device

当执行“ip link set dev {DEVICE} up”时,将会打开net_device。该命令对应到设备接口层,将由dev_open()函数完成具体的打开流程。

/**
 *	dev_open	- prepare an interface for use.
 *	@dev:	device to open
 *
 *	Takes a device from down to up state. The device's private open
 *	function is invoked and then the multicast lists are loaded. Finally
 *	the device is moved into the up state and a %NETDEV_UP message is
 *	sent to the netdev notifier chain.
 *
 *	Calling this function on an active interface is a nop. On a failure
 *	a negative errno code is returned.
 */
int dev_open(struct net_device *dev)
{
    const struct net_device_ops *ops = dev->netdev_ops;
    int ret = 0;

    ASSERT_RTNL(); // 一定是在持有RTNL锁的情况下调用

    // 如果设备已经打开,直接返回打开成功
    if (dev->flags & IFF_UP)
        return 0;

    // 设备必须已经注册或者未挂起,即外部可见
    if (!netif_device_present(dev))
        return -ENODEV;

	// 设置START状态,表示设备已经启动
	set_bit(__LINK_STATE_START, &dev->state);

    // 调用驱动的地址校验回调函数
    if (ops->ndo_validate_addr)
        ret = ops->ndo_validate_addr(dev);

    // 调用驱动的nod_open()回调,驱动程序一般应该在这里清除设备的XOFF标记以开启发送能力
    if (!ret && ops->ndo_open)
        ret = ops->ndo_open(dev);

    if (ret)
        clear_bit(__LINK_STATE_START, &dev->state); // 操作失败,清除START标记
    else {
        // 设置UP标记
        dev->flags |= IFF_UP;
        // Enable NET_DMA
        net_dmaengine_get();
        // Initialize multicasting status
        dev_set_rx_mode(dev);
        // 激活发送队列,主要是配置流量控制相关的队列
        dev_activate(dev);
        // 向内核其它模块发送NETDEV_UP通知事件,表示设备已经打开
        call_netdevice_notifiers(NETDEV_UP, dev);
    }
    return ret;
}

关闭net_device

当执行“ip link set dev DEVICE down”时,设备会被关闭,最后由设备接口层的dev_close()函数负责执行具体的关闭操作。

/**
 *	dev_close - shutdown an interface.
 *	@dev: device to shutdown
 *
 *	This function moves an active device into down state. A
 *	%NETDEV_GOING_DOWN is sent to the netdev notifier chain. The device
 *	is then deactivated and finally a %NETDEV_DOWN is sent to the notifier
 *	chain.
 */
int dev_close(struct net_device *dev)
{
    const struct net_device_ops *ops = dev->netdev_ops;
    ASSERT_RTNL();

    might_sleep();

    // 如果设备本来就是关闭的,那么直接返回成功
    if (!(dev->flags & IFF_UP))
        return 0;

    // 向内核其它模块发送设备即将关闭通知事件
    call_netdevice_notifiers(NETDEV_GOING_DOWN, dev);
    // 清除START状态
    clear_bit(__LINK_STATE_START, &dev->state);

    /* Synchronize to scheduled poll. We cannot touch poll list,
     * it can be even on different cpu. So just clear netif_running().
     *
     * dev->stop() will invoke napi_disable() on all of it's
     * napi_struct instances on this device.
     */
    // 同步其它CPU的状态,让他们能够退出收发状态
    smp_mb__after_clear_bit(); /* Commit netif_running(). */

    // 流量控制相关的清除工作,这会关闭发送队列
    dev_deactivate(dev);

    /*
     *	Call the device specific close. This cannot fail.
     *	Only if device is UP
     *
     *	We allow it to be called even after a DETACH hot-plug
     *	event.
     */
    // 调用驱动程序的ndo_stop()回调
    if (ops->ndo_stop)
        ops->ndo_stop(dev);
    // 清除UP标记
    dev->flags &= ~IFF_UP;

    // 向内核其它模块发送DOWN通知事件,表示设备已经关闭
    call_netdevice_notifiers(NETDEV_DOWN, dev);
    // Shutdown NET_DMA
    net_dmaengine_put();
    return 0;
}

小结

从上面设备打开与关闭过程可以总结如下几个关键点:

  1. 设备打开与否,可以通过net_device.flags中的IFF_UP标记或者net_device.state中的__LINK_STATE_START标记判断,flags标记主要是给内核其它模块或者用户态暴露的;state字段是设备接口层内部自己使用的;
  2. 和net_devcie的注册&注销过程类似,打开与关闭过程中也会向其它模块发送事件通知;
  3. 设备打开与关闭过程中,还有一个非常重要的操作是流量控制机制的启用与停用,这部分见默认网络设备流量控制
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值