netdev_priv函数的分析

190 篇文章 1 订阅

1. 函数netdev_priv分析

[cpp]  view plain copy
  1. include/linux/netdevice.h  
  2. #define NETDEV_ALIGN        32  
  3. #define NETDEV_ALIGN_CONST  (NETDEV_ALIGN - 1)  
  4. static inline void *netdev_priv(struct net_device *dev)  
  5. {  
  6.     return (char *)dev + ((sizeof(struct net_device)+ NETDEV_ALIGN_CONST)  
  7.                 & ~NETDEV_ALIGN_CONST);  
  8. }  

    注意的是:
[cpp]  view plain copy
  1. ((sizeof(struct net_device)+ NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST)  

    此句意思是:给sizeof(struct net_device)加上一定的值,确保加过后的值的大小为32的倍数。即此句的大小是32的倍数。

    这样,当sizeof(struct net_device)的值小于32时,那这句的值32;当sizeof(struct net_device)的值大于32而小于64时,那这句的值64。。。明白了吧。

2. 函数alloc_netdev分析,位于net/core/dev.c

[cpp]  view plain copy
  1. struct net_device *alloc_netdev(int sizeof_priv, const char *name,  
  2.         void (*setup)(struct net_device *))  
  3. {  
  4.     ......  
  5.     /* ensure 32-byte alignment of both the device and private area */  
  6.     alloc_size = (sizeof(*dev) + NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST;  
  7.     alloc_size += sizeof_priv + NETDEV_ALIGN_CONST;  
  8.     p = kzalloc(alloc_size, GFP_KERNEL);    // 对分配的内核内存清0  
  9.     ......  
  10.     if (sizeof_priv)  
  11.         dev->priv = netdev_priv(dev);  
  12.     ......  
  13. }  

    linux/driver/net网卡驱动程序中充满了类似这样的代码:
sturct nic *nic = netdev_priv(dev);
    从文件2中可以看出net_device和网卡私有数据结构是一起分配的,要想获得网卡私有数据结构的地址,文件1中的函数netdev_priv直接返回了net_device结构末端地址,也就是网卡私有数据结构的起始地址。当然其中考虑了字节对齐的问题。至于为什么不直接返回:
sturct nic *nic = dev->priv;

《Linux Devcie Drivers》中说是为了性能和灵活性方面的考虑。

       所以,函数netdev_priv获取网卡的私有数据地址,直接返回了net_device结构末端地址。因为priv成员紧跟在dev结构体后面,返回的也就是priv的首地址。

    看懂了上面两个函数,也就好理解这篇文章了:http://blog.csdn.net/npy_lp/article/details/7090541

[cpp]  view plain copy
  1.   开发平台:Ubuntu 11.04  
  2.   
  3.     编译器:gcc version 4.5.2 (Ubuntu/Linaro 4.5.2-8ubuntu4)  
  4.   
  5.     内核源码:linux-2.6.38.8.tar.bz2  
  6.   
  7.    
  8.   
  9.     1、如何分配struct net_device结构体以及私有数据  
  10.   
  11.     下面将通过实例来讲解Linux内核是如何通过alloc_netdev_mqs函数分配struct net_device结构体以及私有数据的(因为理解了这一点,就能完全理解netdev_priv函数的实现)。  
  12.   
  13.     首先,编写一个模块,代码如下:   
  14. [cpp] view plaincopy  
  15.   
  16.     /* tanglinux.c */    
  17.     #include <linux/module.h>    
  18.     #include <linux/types.h>    
  19.     #include <linux/miscdevice.h>    
  20.     #include <linux/fs.h>    
  21.     #include <linux/netdevice.h>    
  22.     #include <linux/etherdevice.h>    
  23.     #include <linux/kernel.h>    
  24.     #include <linux/ioctl.h>    
  25.         
  26.     #define TANGLINUX _IO('T', 1)    
  27.         
  28.     struct net_local {    
  29.         int count;    
  30.         char ch;    
  31.     };    
  32.         
  33.     static int tanglinux_open(struct inode *inode, struct file *file)    
  34.     {    
  35.         return nonseekable_open(inode, file);    
  36.     }    
  37.         
  38.     static long tanglinux_ioctl(struct file *file, unsigned int cmd, unsigned long arg)    
  39.     {    
  40.         struct net_device *dev;    
  41.         size_t alloc_size;    
  42.         size_t sizeof_priv = sizeof(struct net_local);    
  43.         struct net_device *p;    
  44.             
  45.         switch (cmd) {    
  46.         case TANGLINUX:    
  47.             alloc_size = sizeof(struct net_device);    
  48.             printk("first: alloc_size = %d\n", alloc_size);    
  49.         
  50.             alloc_size += 1; //为验证ALIGN的作用,人为制造net_device结构体的大小不是32位对齐    
  51.         
  52.             if (sizeof_priv) {    
  53.             /* ensure 32-byte alignment of private area */    
  54.             alloc_size = ALIGN(alloc_size, NETDEV_ALIGN); //#define NETDEV_ALIGN    32    
  55.             printk("second: alloc_size = %d\n", alloc_size);    
  56.         
  57.             alloc_size += sizeof_priv;    
  58.             printk("third: alloc_size = %d\n", alloc_size);    
  59.             }    
  60.             /* ensure 32-byte alignment of whole construct */    
  61.             alloc_size += NETDEV_ALIGN - 1;    
  62.             printk("fourth: alloc_size = %d\n", alloc_size);    
  63.             
  64.             p = kzalloc(alloc_size, GFP_KERNEL);    
  65.             if (!p) {    
  66.             printk(KERN_ERR "alloc_netdev: Unable to allocate device.\n");    
  67.             return -ENOMEM;    
  68.             }    
  69.             printk("p = %p\n", p);    
  70.             
  71.             dev = PTR_ALIGN(p, NETDEV_ALIGN);    
  72.             printk("dev = %p\n", dev);    
  73.         
  74.             dev->padded = (char *)dev - (char *)p;    
  75.             
  76.             printk("dev->padded = %d\n", dev->padded);    
  77.         
  78.             kfree(p);    
  79.         
  80.             return 0;    
  81.         default:    
  82.             return -ENOTTY;    
  83.         }    
  84.     }    
  85.         
  86.     static int tanglinux_release(struct inode *inode, struct file *file)    
  87.     {    
  88.         return 0;    
  89.     }    
  90.         
  91.     static const struct file_operations tanglinux_fops = {    
  92.         .owner      = THIS_MODULE,    
  93.         .unlocked_ioctl = tanglinux_ioctl,    
  94.         .open       = tanglinux_open,    
  95.         .release        = tanglinux_release,    
  96.     };    
  97.         
  98.     static struct miscdevice tanglinux_miscdev = {    
  99.         .minor  = WATCHDOG_MINOR,    
  100.         .name   = "tanglinux",    
  101.         .fops   = &tanglinux_fops,    
  102.     };    
  103.         
  104.     static int __init tanglinux_init(void)    
  105.     {    
  106.         printk("tanglinux driver\n");    
  107.         
  108.         return misc_register(&tanglinux_miscdev);    
  109.     }    
  110.         
  111.     static void __exit tanglinux_exit(void)    
  112.     {    
  113.         misc_deregister(&tanglinux_miscdev);    
  114.     }    
  115.         
  116.     module_init(tanglinux_init);    
  117.     module_exit(tanglinux_exit);    
  118.         
  119.     MODULE_LICENSE("GPL");    
  120.   
  121.     然后,编译并加载此模块:   
  122. [cpp] view plaincopy  
  123.   
  124.     //获得Ubuntu 11.04正在运行的内核版本    
  125.     $ cat /proc/version    
  126.     Linux version 2.6.38-13-generic (buildd@roseapple) (gcc version 4.5.2 (Ubuntu/Linaro 4.5.2-8ubuntu4) ) #53-Ubuntu SMP Mon Nov 28 19:23:39 UTC 2011    
  127.         
  128.     //根据上面获得的信息,在Makefile中指定Ubuntu 11.04的内核源码目录为/usr/src/linux-headers-2.6.38-13-generic/    
  129.     # Makefile    
  130.     KERN_DIR = /usr/src/linux-headers-2.6.38-13-generic/    
  131.         
  132.     all:    
  133.         make -C $(KERN_DIR) M=`pwd` modules    
  134.         
  135.     clean:    
  136.         make -C $(KERN_DIR) M=`pwd` modules clean    
  137.         
  138.     obj-m += tanglinux.o    
  139.         
  140.     //编译,并把编译好的模块tanglinux.ko加载到内核中    
  141.     $ make    
  142.     $ sudo insmod tanglinux.ko    
  143.   
  144.     最后,通过测试程序获得相关信息:   
  145. [cpp] view plaincopy  
  146.   
  147.     /* test.c */    
  148.     #include <sys/types.h>    
  149.     #include <sys/stat.h>    
  150.     #include <stdio.h>    
  151.     #include <fcntl.h>    
  152.     #include <unistd.h>    
  153.     #include <sys/ioctl.h>    
  154.         
  155.     #define TANGLINUX _IO('T', 1)    
  156.         
  157.     int main(void)    
  158.     {    
  159.         int fd;    
  160.         
  161.         fd = open("/dev/tanglinux", O_RDWR);    
  162.         if (fd < 0)    
  163.         {    
  164.         printf("can't open /dev/tanglinux\n");    
  165.         return -1;    
  166.         }    
  167.         
  168.         ioctl(fd, TANGLINUX);    
  169.             
  170.         return 0;    
  171.     }    
  172.   
  173. [cpp] view plaincopy  
  174.   
  175.     //编译、执行测试程序,然后通过dmesg命令获得模块输出的信息    
  176.     $ make test    
  177.     $ sudo ./test    
  178.     $ dmesg | tail -7    
  179.     [19853.353282] first: alloc_size = 1088    
  180.     [19853.353296] second: alloc_size = 1120    
  181.     [19853.353306] third: alloc_size = 1128    
  182.     [19853.353316] fourth: alloc_size = 1159    
  183.     [19853.353348] p = cddf6000    
  184.     [19853.353358] dev = cddf6000    
  185.     [19853.353369] dev->padded = 0    
  186.   
  187.     根据Ubuntu 11.04(基于X86硬件平台)中的配置,struct net_device结构体的大小为1088字节,刚好32位对齐,为了验证对齐函数ALIGN的作用,在例子中故意把struct net_device结构体的大小增加了1,所以第二次输出的alloc_size大小为1120个字节,也就是在1089个字节的基础上为了对齐增加了31个字节。  
  188.   
  189.     PTR_ALIGN函数的作用是为了使struct net_device *dev最终得到的内存地址也是32位对齐的。  
  190.   
  191.     上面所讨论的问题都可以通过下面的图示体现出来:  
  192.   
  193.    
  194.   
  195.     2、如何通过netdev_priv访问到其私有数据  
  196.   
  197.     netdev_priv函数的源代码如下:   
  198. [cpp] view plaincopy  
  199.   
  200.     static inline void *netdev_priv(const struct net_device *dev)    
  201.     {    
  202.         return (char *)dev + ALIGN(sizeof(struct net_device), NETDEV_ALIGN);    
  203.     }    
  204.   
  205.     即通过struct net_device *dev首地址加对齐后的偏移量就得到了私有数据的首地址,如上图。  
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值