Chinaunix首页 | 论坛 | 博客
  • 博客访问: 117571
  • 博文数量: 37
  • 博客积分: 236
  • 博客等级: 二等列兵
  • 技术积分: 296
  • 用 户 组: 普通用户
  • 注册时间: 2011-12-18 19:35
文章分类
文章存档

2013年(1)

2012年(36)

我的朋友

分类:

2012-12-11 10:46:51

 
声明:本文为原创
#####请转贴时保留以下内容######
作者GTT
本文档归属http://oldtown.cublog.cn/.转载请注明出处!
请提出宝贵意见Mail:mtloveft@hotmail.com
Linux Version:2.6.33
提示本文是介绍关于linux 如何实现loopback NIC 驱动
 
想对linux协议栈全面了解,网卡驱动是比较基础的。
而loopback设备又是虚拟设备,不涉及到中断和DMA等,所以
还是比较简单的。先从loopback驱动下手的另外一个原因是
它是系统第一个注册的网络驱动程序。
普通的网卡驱动都是以模块化注册到系统的,但loopback驱动
是和kernel一体的,直接在linux启动时被调用。
 
驱动被调用的过程
 
kernel启动时,会执行start_kernel方法,在start_kernel里会初始化很多组件和子系统。
也就是上图的other_init代替了这些初始化过程。start_kernel在执行到最后就会启动init kernel thread。
它会完成剩下的初始化程序。其中在do_initcalls里将会按照顺序执行初始化程序。
其中系统注册过以下方法
subsys_initcall(net_dev_init)      //net/core/dev.c
当执行net_dev_init时,就会调用loopback NIC的驱动程序。

static int __init net_dev_init(void)
{
    ... ...

    if (register_pernet_device(&loopback_net_ops)) goto out;

    ... ...

}

 
当执行register_pernet_device

int register_pernet_device(struct pernet_operations *ops)
{
    int error;
    mutex_lock(&net_mutex);
    error = register_pernet_operations(&pernet_list, ops);
    if (!error && (first_device == &pernet_list))
        first_device = &ops->list;
    mutex_unlock(&net_mutex);
    return error;
}

继续跟进到register_pernet_operations
 

static int register_pernet_operations(struct list_head *list, struct pernet_operations *ops)
{
    int error;

    if (ops->id) {
again:
        error = ida_get_new_above(&net_generic_ids, 1, ops->id);
        if (error < 0) {
            if (error == -EAGAIN) {
                ida_pre_get(&net_generic_ids, GFP_KERNEL);
                goto again;
            }
            return error;
        }
    }
    error = __register_pernet_operations(list, ops);
    if (error) {
        rcu_barrier();
        if (ops->id)
            ida_remove(&net_generic_ids, *ops->id);
    }

    return error;
}

 

看看loopback 注册struct pernet_operations的定义

/* Registered in net/core/dev.c */
struct pernet_operations __net_initdata loopback_net_ops = {
       .init = loopback_net_init,
};

loopback_net_ops没有注册id,所以ops->id为NULL。直接执行 __register_pernet_operations

static int __register_pernet_operations(struct list_head *liststruct pernet_operations *ops)
{
    int err = 0;
    err = ops_init(ops, &init_net);
    if (err) ops_free(ops, &init_net);
    return err;
}

继续跟进ops_init

static int ops_init(const struct pernet_operations *ops, struct net *net)
{
    int err;
    if (ops->id && ops->size) {
        void *data = kzalloc(ops->size, GFP_KERNEL);
        if (!data) return -ENOMEM;

        err = net_assign_generic(net, *ops->id, data);
        if (err) {
            kfree(data);
            return err;
        }
    }
    if (ops->init)
        return ops->init(net);
    return 0;
}


ops->id根本就没被设置,而.init = loopback_net_init,所以 loopback_net_init将被调用,

而loopback_net_init就是loopback NIC的驱动程序,

内容如下

/* Setup and register the loopback device. */
static __net_init int loopback_net_init(struct net *net)
{
    struct net_device *dev;
    int err;

    err = -ENOMEM;
    dev = alloc_netdev(0, "lo", loopback_setup);
//申请一个net_device实例。并进行初始化

    if (!dev) goto out;

    dev_net_set(dev, net);
    err = register_netdev(dev);
//注册 loopback NIC 设备

    if (err) goto out_free_netdev;

    net->loopback_dev = dev;
    return 0;

out_free_netdev:
    free_netdev(dev);
out:
    if (net_eq(net, &init_net))
        panic("loopback: Failed to register netdevice: %d\n", err);
    return err;
}

 alloc_netdev主要分配net_device结构,每个网络设备对象是标准的结构,但是不同的网络驱动程序可能都要维护不同的私有信息,所以在分配net_device结构的同时可以多分配出sizeof_priv大小的结构来。比如应用程序可能会经常查询NIC NIC adress,虽然驱动程序可以通过访问网卡上的存储空间来获
取网卡地址,但是驱动程序可不希望每次都通过慢速的IO 访问来获取这些信息,通常驱动程序会为这些信息维护内存中的数据
结构中,这些信息都可以放在私有信息中。

阅读(1952) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~