版权声明:本文为博主原创文章,未经博主允许不得转载。

开发平台:Ubuntu 11.04

编译器:gcc version 4.5.2 (Ubuntu/Linaro 4.5.2-8ubuntu4)

内核源码:Linux-2.6.38.8.tar.bz2

1、如何分配struct net_device结构体以及私有数据

下面将通过实例来讲解Linux内核是如何通过alloc_netdev_mqs函数分配struct net_device结构体以及私有数据的(因为理解了这一点,就能完全理解netdev_priv函数的实现)。

首先,编写一个模块,代码如下:

  1. /* tanglinux.c */
  2. #include <linux/module.h>
  3. #include <linux/types.h>
  4. #include <linux/miscdevice.h>
  5. #include <linux/fs.h>
  6. #include <linux/netdevice.h>
  7. #include <linux/etherdevice.h>
  8. #include <linux/kernel.h>
  9. #include <linux/ioctl.h>
  10. #define TANGLINUX _IO('T', 1)
  11. struct net_local {
  12. int count;
  13. char ch;
  14. };
  15. static int tanglinux_open(struct inode *inode, struct file *file)
  16. {
  17. return nonseekable_open(inode, file);
  18. }
  19. static long tanglinux_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
  20. {
  21. struct net_device *dev;
  22. size_t alloc_size;
  23. size_t sizeof_priv = sizeof(struct net_local);
  24. struct net_device *p;
  25. switch (cmd) {
  26. case TANGLINUX:
  27. alloc_size = sizeof(struct net_device);
  28. printk("first: alloc_size = %d\n", alloc_size);
  29. alloc_size += 1; //为验证ALIGN的作用,人为制造net_device结构体的大小不是32位对齐
  30. if (sizeof_priv) {
  31. /* ensure 32-byte alignment of private area */
  32. alloc_size = ALIGN(alloc_size, NETDEV_ALIGN); //#define NETDEV_ALIGN    32
  33. printk("second: alloc_size = %d\n", alloc_size);
  34. alloc_size += sizeof_priv;
  35. printk("third: alloc_size = %d\n", alloc_size);
  36. }
  37. /* ensure 32-byte alignment of whole construct */
  38. alloc_size += NETDEV_ALIGN - 1;
  39. printk("fourth: alloc_size = %d\n", alloc_size);
  40. p = kzalloc(alloc_size, GFP_KERNEL);
  41. if (!p) {
  42. printk(KERN_ERR "alloc_netdev: Unable to allocate device.\n");
  43. return -ENOMEM;
  44. }
  45. printk("p = %p\n", p);
  46. dev = PTR_ALIGN(p, NETDEV_ALIGN);
  47. printk("dev = %p\n", dev);
  48. dev->padded = (char *)dev - (char *)p;
  49. printk("dev->padded = %d\n", dev->padded);
  50. kfree(p);
  51. return 0;
  52. default:
  53. return -ENOTTY;
  54. }
  55. }
  56. static int tanglinux_release(struct inode *inode, struct file *file)
  57. {
  58. return 0;
  59. }
  60. static const struct file_operations tanglinux_fops = {
  61. .owner      = THIS_MODULE,
  62. .unlocked_ioctl = tanglinux_ioctl,
  63. .open       = tanglinux_open,
  64. .release        = tanglinux_release,
  65. };
  66. static struct miscdevice tanglinux_miscdev = {
  67. .minor  = WATCHDOG_MINOR,
  68. .name   = "tanglinux",
  69. .fops   = &tanglinux_fops,
  70. };
  71. static int __init tanglinux_init(void)
  72. {
  73. printk("tanglinux driver\n");
  74. return misc_register(&tanglinux_miscdev);
  75. }
  76. static void __exit tanglinux_exit(void)
  77. {
  78. misc_deregister(&tanglinux_miscdev);
  79. }
  80. module_init(tanglinux_init);
  81. module_exit(tanglinux_exit);
  82. MODULE_LICENSE("GPL");

然后,编译并加载此模块:

  1. //获得Ubuntu 11.04正在运行的内核版本
  2. $ cat /proc/version
  3. 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
  4. //根据上面获得的信息,在Makefile中指定Ubuntu 11.04的内核源码目录为/usr/src/linux-headers-2.6.38-13-generic/
  5. # Makefile
  6. KERN_DIR = /usr/src/linux-headers-2.6.38-13-generic/
  7. all:
  8. make -C $(KERN_DIR) M=`pwd` modules
  9. clean:
  10. make -C $(KERN_DIR) M=`pwd` modules clean
  11. obj-m += tanglinux.o
  12. //编译,并把编译好的模块tanglinux.ko加载到内核中
  13. $ make
  14. $ sudo insmod tanglinux.ko

最后,通过测试程序获得相关信息:

  1. /* test.c */
  2. #include <sys/types.h>
  3. #include <sys/stat.h>
  4. #include <stdio.h>
  5. #include <fcntl.h>
  6. #include <unistd.h>
  7. #include <sys/ioctl.h>
  8. #define TANGLINUX _IO('T', 1)
  9. int main(void)
  10. {
  11. int fd;
  12. fd = open("/dev/tanglinux", O_RDWR);
  13. if (fd < 0)
  14. {
  15. printf("can't open /dev/tanglinux\n");
  16. return -1;
  17. }
  18. ioctl(fd, TANGLINUX);
  19. return 0;
  20. }
  1. //编译、执行测试程序,然后通过dmesg命令获得模块输出的信息
  2. $ make test
  3. $ sudo ./test
  4. $ dmesg | tail -7
  5. [19853.353282] first: alloc_size = 1088
  6. [19853.353296] second: alloc_size = 1120
  7. [19853.353306] third: alloc_size = 1128
  8. [19853.353316] fourth: alloc_size = 1159
  9. [19853.353348] p = cddf6000
  10. [19853.353358] dev = cddf6000
  11. [19853.353369] dev->padded = 0

根据Ubuntu 11.04(基于X86硬件平台)中的配置,struct net_device结构体的大小为1088字节,刚好32位对齐,为了验证对齐函数ALIGN的作用,在例子中故意把struct net_device结构体的大小增加了1,所以第二次输出的alloc_size大小为1120个字节,也就是在1089个字节的基础上为了对齐增加了31个字节。

PTR_ALIGN函数的作用是为了使struct net_device *dev最终得到的内存地址也是32位对齐的。

上面所讨论的问题都可以通过下面的图示体现出来:

2、如何通过netdev_priv访问到其私有数据

netdev_priv函数的源代码如下:

  1. static inline void *netdev_priv(const struct net_device *dev)
  2. {
  3. return (char *)dev + ALIGN(sizeof(struct net_device), NETDEV_ALIGN);
  4. }
 

即通过struct net_device *dev首地址加对齐后的偏移量就得到了私有数据的首地址,如上图。

网络驱动移植之例解netdev_priv函数的更多相关文章

  1. 网络驱动移植之net_device结构体及其相关的操作函数

    内核源码:Linux-2.6.38.8.tar.bz2 在Linux系统中,网络设备都被抽象为struct net_device结构体.它是网络设备硬件与上层协议之间联系的接口,了解它对编写网络驱动程 ...

  2. 网络驱动移植之解析Linux网络驱动的基本框架

    内核源码:linux-2.6.38.8.tar.bz2 概括而言,编写Linux网络驱动其实只要完成两件事即可,一是分配并初始化网络设备,二是注册网络设备. 1.分配并初始化网络设备 动态分配网络设备 ...

  3. 网络驱动移植之简述CS8900A网络芯片的基本原理

    CS8900A数据手册:http://www.cirrus.com/cn/products/cs8900a.html 1.概述 CS8900A是CIRRUS LOGIC公司生产的低功耗.性能优越的16 ...

  4. Linux 网卡驱动学习(一)(分析一个虚拟硬件的网络驱动样例)

    在Linux,网络分为两个层,各自是网络堆栈协议支持层,以及接收和发送网络协议的设备驱动程序层. 网络堆栈是硬件中独立出来的部分.主要用来支持TCP/IP等多种协议,网络设备驱动层是连接网络堆栈协议层 ...

  5. Android安卓书籍推荐《Android驱动开发与移植实战详解》下载

    百度云下载地址:点我 Android凭借其开源性.优异的用户体验和极为方便的开发方式,赢得了广大用户和开发者的青睐,目前已经发展成为市场占有率很高的智能手机操作系统. <Android驱动开发与 ...

  6. Linux网络驱动--snull

    snull是<Linux Device Drivers>中的一个网络驱动的例子.这里引用这个例子学习Linux网络驱动. 因为snull的源码,网上已经更新到适合最新内核,而我自己用的还是 ...

  7. DM9000驱动移植在mini2440(linux2.6.29)和FS4412(linux3.14.78)上的实现(deep dive)篇一

    关于dm9000的驱动移植分为两篇,第一篇在mini2440上实现,基于linux2.6.29,也成功在在6410上移植了一遍,和2440非常类似,第二篇在fs4412(Cortex A9)上实现,基 ...

  8. Windows网络驱动、NDIS驱动(微端口驱动、中间层驱动、协议驱动)、TDI驱动(网络传输层过滤)、WFP(Windows Filtering Platform)

    catalog . 引言 . Windows 2000网络结构和OSI模型 . NDIS驱动 . NDIS微端口驱动编程实例 . NDIS中间层驱动编程实例 . NDIS协议层驱动编程实例 . TDI ...

  9. SPI在linux3.14.78 FS_S5PC100(Cortex A8)和S3C2440上驱动移植(deep dive)

    由于工作的原因,对SPI的理解最为深刻,也和SPI最有感情了,之前工作都是基于OSEK操作系统上进行实现,也在US/OS3上实现过SPI驱动的实现和测试,但是都是基于基本的寄存器操作,没有一个系统软件 ...

随机推荐

  1. POJ 3169 Layout(差分约束 线性差分约束)

    题意: 有N头牛, 有以下关系: (1)A牛与B牛相距不能大于k (2)A牛与B牛相距不能小于k (3)第i+1头牛必须在第i头牛前面 给出若干对关系(1),(2) 求出第N头牛与第一头牛的最长可能距 ...

  2. [MVC]Area区域相关技术

    MVC提供Area机制,在同一个项目之内就能够切割出不同的ASP.NET MVC网站. 插入:首先在相同的位置,比如说同一个文件夹(如:Controllers)是不能创建俩个相同名称的文件(如:Hom ...

  3. 简单的MVC 权限管理

    花了3天时间研究了下对于 NHibernate+MVC4+bootstrap+Redis(这个是选配只做了登陆测试)+T4 这些都是第一次使用.用着有些生硬权当鼓励下自己,记录下来有空就继续完善. 思 ...

  4. php 数据库的增删改查

    <!DOCTYPE html><html><head> <meta charset="UTF-8"> <title>&l ...

  5. hexo干货系列:(总纲)搭建独立博客初衷

    前言 我是一名程序员,以前知识整理都是整理在为知笔记上,博客用的比较少,更别说是使用独立博客,因为不会... 2016年过年在家期间偶然的机会萌发了自己要搭建一个属于自己的独立博客的想法,于是就有了下 ...

  6. CodeForces 556 --Case of Fake Numbers

    B. Case of Fake Numbers time limit per test 2 seconds memory limit per test 256 megabytes input stan ...

  7. PTA 04-树5 Root of AVL Tree (25分)

    题目地址 https://pta.patest.cn/pta/test/16/exam/4/question/668 5-6 Root of AVL Tree   (25分) An AVL tree ...

  8. Spring Boot Reactive Streams

    1 响应式编程规范 目标:provide a standard for asynchronous stream processing with non-blocking backpressure ht ...

  9. HTTP API 自动化测试从手工测试到平台的演变

    不管是 Web 系统,还是移动 APP,前后端逻辑的分离设计已经是常态化,相互之间通过 API 调用进行数据交互.在基于 API 约定的开发模式下,如何加速请求 / 响应的 API 测试,让研发人员及 ...

  10. THUWC2018 暴力+爆炸记

    Day 0 没有Day0. Day 1 签到然后去宿舍,环境还行,比某偏远山区要强多了,不过这热水有点难拿??看RP有遇到煮好水的饮水机就拿,没有就苟矿泉水. 中午,那个餐还是挺好吃的,不过餐费40就 ...