net_device的注册与注销


net_device的分配与释放中的介绍,net_device对象只有通过register_netdev()注册到系统后才能被外部感知到。类似的,在释放之前需要通过unregister_netdev()将net_device对象先从系统中注销。这篇笔记分析了这两个过程的实现。

RTNL锁

在分析注册和注销过程之前,先来看个RTNL锁,因为这两个过程都由这把锁保护,代码如下:

static DEFINE_MUTEX(rtnl_mutex);

void rtnl_lock(void)
{
   
    mutex_lock(&rtnl_mutex);
}

void __rtnl_unlock(void)
{
   
    mutex_unlock(&rtnl_mutex);
}

void rtnl_unlock(void)
{
   
    mutex_unlock(&rtnl_mutex);
    // 释放锁后执行了一些其它工作,见下面的分析
    netdev_run_todo();
}

这是一个互斥锁,这意味着net_device的中注册和注销不能在原子上下文中使用。

注册net_device

分配好net_device对象并进行初始化后,驱动程序就可以通过register_netdev()向系统注册该net_device对象了。

/**
 *	register_netdev	- register a network device
 *	@dev: device to register
 *
 *	Take a completed network device structure and add it to the kernel
 *	interfaces. A %NETDEV_REGISTER message is sent to the netdev notifier
 *	chain. 0 is returned on success. A negative errno code is returned
 *	on a failure to set up the device, or if the name is a duplicate.
 *
 *	This is a wrapper around register_netdevice that takes the rtnl semaphore
 *	and expands the device name if you passed a format string to
 *	alloc_netdev.
 */
int register_netdev(struct net_device *dev)
{
   
    int err;

    rtnl_lock(); // 持锁情况下执行注册过程

    // 如果驱动程序指定的网络设备名称中有%字符,则内核认为传入的是一个格式化字符串,
    // 会尝试为其分配一个唯一的ID,以此组成最终的网络设备名称。比如传入
    // "eth%d", 最终的结果是"eth0"、"eth1"等等
    if (strchr(dev->name, '%')) {
   
        err = dev_alloc_name(dev, dev->name);
        if (err < 0)
            goto out;
    }
    // 执行真正的注册流程
    err = register_netdevice(dev);
out:
    rtnl_unlock();
    return err;
}

register_netdevice()

  1. 继续初始化net_device的一些字段;
  2. 如果有指定那么执行ndo_init()回调函数,如果返回失败那么也会导致注册过程失败;
  3. 确保net_device的名称在namespace内是唯一的。在namespace内分配一个唯一的ifindex;
  4. 将net_device对象添加到全局数据结构中;
  5. 发送设备注册通知事件;
int register_netdevice(struct net_device *dev)
{
   
    struct hlist_head *head;
    struct hlist_node *p;
    int ret;
    struct net *net = dev_net(dev);
	
    // 设备接口层必须已经初始化完成,即net_dev_init()已经执行完毕
    BUG_ON(dev_boot_phase);
    ASSERT_RTNL(); // 确保在持有RTNL锁的情况下调用

    might_sleep();

    // 网络设备的注册状态必须是UNINITIALIZED,刚分配的net_device就是这个状态
    BUG_ON(dev->reg_state != NETREG_UNINITIALIZED);
    BUG_ON(!net);

    // 初始化地址列表、队列锁
    spin_lock_init(&dev->addr_list_lock);
    netdev_set_addr_lockdep_class(dev);
    netdev_init_queue_locks(dev);

    dev->iflink = -1;

    // 执行驱动程序提供的ndo_init()回调函数
    if (dev->netdev_ops->ndo_init) {
   
        ret = dev->netdev_ops->ndo_init(dev);
        if (ret) {
   
            if (ret > 0)
                ret = -EIO;
            goto out;
        }
    }
    // 校验net_device对象的名称
    if (!dev_valid_name(dev->name)) {
   
        ret = -EINVAL;
        goto err_uninit;
    }
    // 分配网络设备索引
    dev->ifindex = dev_new_index(net);
    if (dev->iflink == -
  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值