Chinaunix首页 | 论坛 | 博客
  • 博客访问: 628261
  • 博文数量: 155
  • 博客积分: 5688
  • 博客等级: 大校
  • 技术积分: 2134
  • 用 户 组: 普通用户
  • 注册时间: 2010-05-15 15:12
文章分类

全部博文(155)

文章存档

2011年(58)

2010年(97)

分类: LINUX

2010-09-06 22:58:34

声明:本文为原创
#####请转贴时保留以下内容######
作者GTT
本文档归属http://oldtown.cublog.cn/.转载请注明出处!
请提出宝贵意见Mail:mtloveft@hotmail.com
Linux Version:2.6.33
提示本文是介绍关于linux 如何实现loopback NIC 驱动
 
接着分析alloc_netdev方法

#define alloc_netdev(sizeof_priv, name, setup) \
    alloc_netdev_mq(sizeof_priv, name, setup, 1)

 
只是调用alloc_netdev_mq方法,方法声明如下

struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name,
        void (*setup)(struct net_device *), unsigned int queue_count)

 
alloc_netdev_mq参数意义如下
第一个参数sizeof_priv是每个网络设备的私有数据的大小,也就是net_device结构中的priv的大小。
第二个参数name是设备名,传递进来一般都是一个未format的字符串,比如"eth%d",在方法里多个相同类型NIC device会依次为eth0,eth1...
第三个参数setup是一个初始化net_device结构的call back方法。
第四个参queue_count数是NIC device的Queue的大小
 
alloc_netdev_mq的代码如下

/**
 * alloc_netdev_mq - allocate network device
 * @sizeof_priv: size of private data to allocate space for
 * @name: device name format string
 * @setup: callback to initialize device
 * @queue_count: the number of subqueues to allocate
 *
 * Allocates a struct net_device with private data area for driver use
 * and performs basic initialization. Also allocates subquue structs
 * for each queue on the device at the end of the netdevice.
 */

struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name,
        void (*setup)(struct net_device *), unsigned int queue_count)
{
    struct netdev_queue *tx;
    struct net_device *dev;
    size_t alloc_size;
    struct net_device *p;

    BUG_ON(strlen(name) >= sizeof(dev->name));

    alloc_size = sizeof(struct net_device);
    if (sizeof_priv) {
        /* ensure 32-byte alignment of private area */
        alloc_size = ALIGN(alloc_size, NETDEV_ALIGN);
        alloc_size += sizeof_priv;
    }
    /* ensure 32-byte alignment of whole construct */
    alloc_size += NETDEV_ALIGN - 1;

    p = kzalloc(alloc_size, GFP_KERNEL);
    if (!p) {
        printk(KERN_ERR "alloc_netdev: Unable to allocate device.\n");
        return NULL;
    }

    tx = kcalloc(queue_count, sizeof(struct netdev_queue), GFP_KERNEL);
    if (!tx) {
        printk(KERN_ERR "alloc_netdev: Unable to allocate " "tx qdiscs.\n");
        goto free_p;
    }

    dev = PTR_ALIGN(p, NETDEV_ALIGN);
//PTR_ALIGN 内存对齐,比如按32byte对齐
    dev->padded = (char *)dev - (char *)p;

    if (dev_addr_init(dev)) goto free_tx;

    dev_unicast_init(dev);
    dev_net_set(dev, &init_net);

    dev->_tx = tx;
    dev->num_tx_queues = queue_count;
    dev->real_num_tx_queues = queue_count;
    dev->gso_max_size = GSO_MAX_SIZE;

    netdev_init_queues(dev);

    INIT_LIST_HEAD(&dev->napi_list);
    INIT_LIST_HEAD(&dev->unreg_list);
    INIT_LIST_HEAD(&dev->link_watch_list);
    dev->priv_flags = IFF_XMIT_DST_RELEASE;
    setup(dev);
    strcpy(dev->name, name);
    return dev;

free_tx:
    kfree(tx);

free_p:
    kfree(p);
    return NULL;
}

 
首先分配内存空间,先计算分配空间的大小。sizeof_priv虽然这里为零,但是
其他网卡驱动sizeof_priv基本都不为0的。
ALIGN(alloc_size, NETDEV_ALIGN)这里NETDEV_ALIGN为32
关联定义如下

#define NETDEV_ALIGN 32

#define ALIGN(x,a)               __ALIGN_MASK(x,(typeof(x))(a)-1)
#define __ALIGN_MASK(x,mask)    (((x)+(mask))&~(mask))
#define PTR_ALIGN(p, a)         ((typeof(p))ALIGN((unsigned long)(p), (a)))

 
ALIGN(x,a)就是按照a的整数倍数来分配X的大小,说的有点绕藤了。
比如x=1,a=32, 计算结果就为32, 如果x=33,a=32,那么结果就为32*2,既64了。
最后非配内存结构图如下
 
 
dev_addr_init是对device的地址进行初始化

static int dev_addr_init(struct net_device *dev)
{
    unsigned char addr[MAX_ADDR_LEN];
    struct netdev_hw_addr *ha;
    int err;

    /* rtnl_mutex must be held here */

    __hw_addr_init(&dev->dev_addrs);
    memset(addr, 0, sizeof(addr));
    err = __hw_addr_add(&dev->dev_addrs, addr, sizeof(addr), NETDEV_HW_ADDR_T_LAN);
    if (!err) {
        
/* Get the first (previously created) address from the list
         * and set dev_addr pointer to this location.
         */

        ha = list_first_entry(&dev->dev_addrs.list, struct netdev_hw_addr, list);
        dev->dev_addr = ha->addr;
    }
    return err;
}

MAX_ADDR_LEN大小为32,默认Device地址最大长度就为32。

#define MAX_ADDR_LEN 32 /* Largest hardware address length */

 
__hw_addr_init只是对device的硬件地址的双向链表进行初始化。

static void __hw_addr_init(struct netdev_hw_addr_list *list)
{
    INIT_LIST_HEAD(&list->list);
    list->count = 0;
}

 
__hw_addr_add是真正的设置device的硬件地址,但也是设为32byte的0。
首先判断地址是否存在,不存在的话,重新分配一个struct netdev_hw_addr,
并把addr付给它,把它加入到device的dev->dev_addrs链表上。
 

/* hw addresses list handling functions */
static int __hw_addr_add(struct netdev_hw_addr_list *list, unsigned char *addr,
             int addr_len, unsigned char addr_type)
{
    struct netdev_hw_addr *ha;
    int alloc_size;

    if (addr_len > MAX_ADDR_LEN) return -EINVAL;

    list_for_each_entry(ha, &list->list, list) {
        if (!memcmp(ha->addr, addr, addr_len) &&
            ha->type == addr_type) {
            ha->refcount++;
            return 0;
        }
    }

    alloc_size = sizeof(*ha);
    if (alloc_size < L1_CACHE_BYTES) alloc_size = L1_CACHE_BYTES;
    ha = kmalloc(alloc_size, GFP_ATOMIC);
    if (!ha) return -ENOMEM;
    memcpy(ha->addr, addr, addr_len);
    ha->type = addr_type;
    ha->refcount = 1;
    ha->synced = false;
    list_add_tail_rcu(&ha->list, &list->list);
    list->count++;
    return 0;
}

 
地址双向链表关系如下
 
 
也就是一个device可以有多个硬件地址,以及unicast地址,理论上也可以由多个mac地址。
 
阅读(1712) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~