声明:本文为原创
#####请转贴时保留以下内容######
作者:GTT
请提出宝贵意见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地址。
阅读(783) | 评论(0) | 转发(0) |