您的位置:首页 > 运维架构 > Linux

Linux设备驱动程序(LDD)中snull的编译问题

2015-12-21 22:06 671 查看
对LDD中snull程序,编译的时候会有许多问题,鉴于网上还没有合适的解决办法,做此总结,整理知识。本文在debian6.0上运行通过,内核版本为2.6.32。
学习LDD中网络驱动程序部分,理解snull程序的原理很有必要。snull不依赖于硬件,数据包的收发都属于内存操作,但对整个网络驱动程序原 理已经做了很好的阐述。程序并不复杂,相比e100.c;8139too.c;pci-skeleton.c,容易理解的多。作者写这本书的时候尚是 2.6.11的年代,与现在内核版本相比,有些接口发生了变化,这是snull编译失败的直接原因。本文将描述snull的修改方法,并指出发生变化的接
口。本文在debian6.0上运行通过,内核版本为2.6.32。
本文提供了修改完成后的makefile和snull.c,并生成了patch文件。
 


本文内容

1)常见问题

2)正确的snull编译方法

3)文件下载


一 常见问题

    这是我自己遇到的,和网上看到的部分问题,现一一阐述原因,并在第二段(见下文)中阐述解决方法。 如果在这些问题之外,还有问题,清大家留言,方便讨论。至于详细的接口变化,我会另写文章,一一说明。
 
    1)错误描述:

make -C /lib/modules/2.6.32-5-686/build M=/home/xiebiwei/dev/code/Ldd/snull modules

make: *** /lib/modules/2.6.32-5-686/build: No such file or directory.  Stop.

make: *** [default] Error 2
            问题原因:没有安装内核源代码树,或者是安装了内核源代码树后,没有修改makefile中的kerneldir。
 
     2)错误描述:

make -C /lib/modules/2.6.32/build M=/home/xiebiwei/dev/code/Ldd/snull modules

make[1]: Entering directory `/usr/src/linux-source-2.6.32'

scripts/Makefile.build:49: *** CFLAGS was changed in "/home/xiebiwei/dev/code/Ldd/snull/Makefile". Fix it to use EXTRA_CFLAGS.  Stop.

make[1]: *** [_module_/home/xiebiwei/dev/code/Ldd/snull] Error 2

make[1]: Leaving directory `/usr/src/linux-source-2.6.32'

make: *** [default] Error 2
            问题原因:内核版本不同,最近版本已经把CFLAGS变为EXTRA_CFLAGS
 
      3)错误描述:

make -C /lib/modules/2.6.32/build M=/home/xiebiwei/dev/code/Ldd/snull modules

make[1]: Entering directory `/usr/src/linux-source-2.6.32'

  CC [M]  /home/xiebiwei/dev/code/Ldd/snull/snull.o

/home/xiebiwei/dev/code/Ldd/snull/snull.c:18:26: error: linux/config.h: No such file or directory

/home/xiebiwei/dev/code/Ldd/snull/snull.c: In function ‘snull_poll’:

/home/xiebiwei/dev/code/Ldd/snull/snull.c:289: error: ‘struct net_device’ has no member named ‘quota’

/home/xiebiwei/dev/code/Ldd/snull/snull.c:289: warning: type defaults to ‘int’ in declaration of ‘_min1’

/home/xiebiwei/dev/code/Ldd/snull/snull.c:289: error: ‘struct net_device’ has no member named ‘quota’

/home/xiebiwei/dev/code/Ldd/snull/snull.c:319: error: ‘struct net_device’ has no member named ‘quota’

/home/xiebiwei/dev/code/Ldd/snull/snull.c:321: error: implicit declaration of function ‘netif_rx_complete’

/home/xiebiwei/dev/code/Ldd/snull/snull.c: In function ‘snull_napi_interrupt’:

/home/xiebiwei/dev/code/Ldd/snull/snull.c:406: error: implicit declaration of function ‘netif_rx_schedule’

/home/xiebiwei/dev/code/Ldd/snull/snull.c: In function ‘snull_init’:

/home/xiebiwei/dev/code/Ldd/snull/snull.c:647: error: ‘struct net_device’ has no member named ‘open’

/home/xiebiwei/dev/code/Ldd/snull/snull.c:648: error: ‘struct net_device’ has no member named ‘stop’

/home/xiebiwei/dev/code/Ldd/snull/snull.c:649: error: ‘struct net_device’ has no member named ‘set_config’

/home/xiebiwei/dev/code/Ldd/snull/snull.c:650: error: ‘struct net_device’ has no member named ‘hard_start_xmit’

/home/xiebiwei/dev/code/Ldd/snull/snull.c:651: error: ‘struct net_device’ has no member named ‘do_ioctl’

/home/xiebiwei/dev/code/Ldd/snull/snull.c:652: error: ‘struct net_device’ has no member named ‘get_stats’

/home/xiebiwei/dev/code/Ldd/snull/snull.c:653: error: ‘struct net_device’ has no member named ‘change_mtu’

/home/xiebiwei/dev/code/Ldd/snull/snull.c:654: error: ‘struct net_device’ has no member named ‘rebuild_header’

/home/xiebiwei/dev/code/Ldd/snull/snull.c:655: error: ‘struct net_device’ has no member named ‘hard_header’

/home/xiebiwei/dev/code/Ldd/snull/snull.c:656: error: ‘struct net_device’ has no member named ‘tx_timeout’

/home/xiebiwei/dev/code/Ldd/snull/snull.c:659: error: ‘struct net_device’ has no member named ‘poll’

/home/xiebiwei/dev/code/Ldd/snull/snull.c:660: error: ‘struct net_device’ has no member named ‘weight’

/home/xiebiwei/dev/code/Ldd/snull/snull.c:665: error: ‘struct net_device’ has no member named ‘hard_header_cache’

make[2]: *** [/home/xiebiwei/dev/code/Ldd/snull/snull.o] Error 1

make[1]: *** [_module_/home/xiebiwei/dev/code/Ldd/snull] Error 2

make[1]: Leaving directory `/usr/src/linux-source-2.6.32'

make: *** [default] Error 2
      问题原因:

1  config.h在2.6.32内核中已经不存在,需要用相应头文件替换

2  struct net_device 的结构在新版本内核中发生了变化,删去了quota成员;将(open,stop,set_config,hard_start_xmit等)封装进了 struct net_device_ops;将(poll,weight等)封装进了 struct napi_struct;将(hard_header,hard_header_cache,rebuild等)封装进了struct header_ops。并对部分函数名和参数进行了变动。

3  netif_rx_complete和netif_rx_schedule属于poll机制中的函数,接口名称已经变为napi_complete和napi_schedule。
 
 
 


二 正确的snull编译方法

1)构造内核源代码树

     这是编写驱动程序的必要准备,否则会无法编译驱动程序。模块在编译的时候必须调用内核的函数(模块属于内核的一部分,无法调用glibc),故而构造源代码树很必要。

     请参考:debian上的详细步骤:http://blog.csdn.net/xiebiwei/archive/2011/02/20/6196818.aspx

     debian中下载kernel比较方便,而比较通用的下载kernel方式如下:         

     用 "  uname -r " 查看系统内核版本,到 linux的kernel网站(http://www.kernel.org/pub/linux/kernel/v2.6/ )查找相应版本的内核源文件,下载并将其置于"/usr/src/"下。

     接下来便可用上述链接中的方法解压缩内核源代码并编译了。        

 

2)修改MakeFile

I)  将CFLAGS修改为EXTRA_CFLAGS,属于内核升级带来的接口变化。查看

II)修改KERNELDIR为正确的模块编译目录,即构造内核源代码树时生成的目录,一般为" /lib/modules /**/build"。查看    

 

3)修改源文件snull.c

I)头文件中的<linux/config.h>,在新内核中已经被删除,查看老版本内核的该文件内容,并替换。查看  

II) 修改 struct snull_priv ,添加struct napi_struct、struct net_device两个结构体的成员变量。2.6.32内核将poll()、weight等封装进了napi_struct,故而想实现轮询机制必须在 private中定义napi_struct。  查看                

III) 修改函数:snull_poll。2.6.32内核中,struct net_device去除了quota,quota是设备对接收数据包数量的限 制;poll函数接口参数也发生了变化,变为了 static int (*poll)(struct napi_struct,int),故而函数体也需要稍做调整,比如priv指针的获取等。查看  

IV) 修改函数snull_napi_interrupt,该函数中调度poll的函数接口变为了napi_schedule(struct napi_struct *)。查看  

V)   修改函数snull_init。struct net_device的定义发生了变化。查看

将open、stop、set_config等操作封装进了结构体 struct net_device_ops。查看

将harder_header、rebuild_header等操作封装进了struct header_ops;poll则封装进了struct napi_stuct。查看


三 示例文件下载

下载链接 (包括snull.c makefile snull_2.6.32.patch)

使用方法:可以直接覆盖snull.c和makefile。也可以只将patch文件拷贝到snull/下后运行patch -p1 < snull_2.6.32.patch

patch文件

diff -uNr snull_original/Makefile snull/Makefile

--- snull_original/Makefile 2005-01-31 15:31:02.000000000 -0500

+++ snull/Makefile 2011-02-24 17:45:39.000000000 -0500

@@ -9,8 +9,8 @@

   DEBFLAGS = -O2

 endif
 
-CFLAGS += $(DEBFLAGS)

-CFLAGS += -I..
+EXTRA_CFLAGS += $(DEBFLAGS)

+EXTRA_CFLAGS += -I..
 

 ifneq ($(KERNELRELEASE),)

 # call from kernel build system

@@ -19,7 +19,7 @@

 

 else

  
-KERNELDIR ?= /lib/modules/$(shell uname -r)/build
+KERNELDIR ?= /lib/modules/2.6.32/build
 PWD       := $(shell pwd)

 

 default:

diff -uNr snull_original/snull.c snull/snull.c

--- snull_original/snull.c 2005-01-31 15:31:02.000000000 -0500

+++ snull/snull.c 2011-02-26 19:50:06.000000000 -0500

@@ -14,8 +14,10 @@

  *

  * $Id: snull.c,v 1.21 2004/11/05 02:36:03 rubini Exp $

  */


-#include <linux/config.h>
+#ifdef LINUX_CONFIG_H

+#define LINUX_CONFIG_H

+#include <linux/autoconf.h>

+#endif
 #include <linux/module.h>

 #include <linux/init.h>

 #include <linux/moduleparam.h>

@@ -87,6 +89,9 @@

  u8 *tx_packetdata;

  struct sk_buff *skb;

  spinlock_t lock;

+     
+      struct napi_struct napi;

+      struct net_device *dev;
 };

 

 static void snull_tx_timeout(struct net_device *dev);

@@ -284,11 +289,12 @@

 /*

  * The poll implementation.

  */

-static int snull_poll(struct net_device *dev, int *budget)
+static int snull_poll(struct napi_struct *napi, int budget)
 {
- int npackets = 0, quota = min(dev->quota, *budget);
+ int npackets = 0, quota = budget;
  struct sk_buff *skb;
- struct snull_priv *priv = netdev_priv(dev);
+ struct snull_priv *priv = container_of(napi,struct snull_priv,napi);

+      struct net_device *dev=priv->dev;
  struct snull_packet *pkt;

    

  while (npackets < quota && priv->rx_queue) {

@@ -315,10 +321,8 @@

   snull_release_buffer(pkt);

  }

  /* If we processed all packets, we're done; tell the kernel and reenable ints */
- *budget -= npackets;
- dev->quota -= npackets;

  if (! priv->rx_queue) {
-  netif_rx_complete(dev);
+  napi_complete(&priv->napi);
   snull_rx_ints(dev, 1);

   return 0;

  }

@@ -403,7 +407,7 @@

  priv->status = 0;

  if (statusword & SNULL_RX_INTR) {

   snull_rx_ints(dev, 0);  /* Disable further interrupts */
-   netif_rx_schedule(dev);
+  napi_schedule(&priv->napi);
  }

  if (statusword & SNULL_TX_INTR) {

          /* a transmission is over: free the skb */

@@ -585,8 +589,8 @@

 
 

 int snull_header(struct sk_buff *skb, struct net_device *dev,
-                unsigned short type, void *daddr, void *saddr,

-                unsigned int len)
+                unsigned short type, const void *daddr, const void *saddr,

+                unsigned len)
 {

  struct ethhdr *eth = (struct ethhdr *)skb_push(skb,ETH_HLEN);

 

@@ -627,6 +631,25 @@

  * The init function (sometimes called probe).

  * It is invoked by register_netdev()

  */


+static const struct net_device_ops snull_dev_ops = {

+

+ .ndo_open  =snull_open,

+ .ndo_stop  =snull_release,

+ .ndo_set_config =snull_config,

+ .ndo_start_xmit =snull_tx,

+ .ndo_do_ioctl =snull_ioctl,

+ .ndo_get_stats =snull_stats,

+ .ndo_change_mtu =snull_change_mtu,

+ .ndo_tx_timeout =snull_tx_timeout,

+};

+static const struct header_ops snull_header_ops= {

+ .create =snull_header,

+ .rebuild =snull_rebuild_header,

+ .cache = NULL,             /* Disable caching */

+};

 void snull_init(struct net_device *dev)

 {

  struct snull_priv *priv;

@@ -644,25 +667,13 @@

   */

  ether_setup(dev); /* assign some of the fields */

 
- dev->open            = snull_open;

- dev->stop            = snull_release;

- dev->set_config      = snull_config;

- dev->hard_start_xmit = snull_tx;

- dev->do_ioctl        = snull_ioctl;

- dev->get_stats       = snull_stats;

- dev->change_mtu      = snull_change_mtu; 

- dev->rebuild_header  = snull_rebuild_header;

- dev->hard_header     = snull_header;

- dev->tx_timeout      = snull_tx_timeout;
+ dev->netdev_ops = &snull_dev_ops;

+ dev->header_ops = &snull_header_ops;
  dev->watchdog_timeo = timeout;
- if (use_napi) {

-  dev->poll        = snull_poll;

-  dev->weight      = 2;

- }
+

  /* keep the default flags, just add NOARP */

  dev->flags           |= IFF_NOARP;

  dev->features        |= NETIF_F_NO_CSUM;
- dev->hard_header_cache = NULL;      /* Disable caching */
 

  /*

   * Then, initialize the priv field. This encloses the statistics

@@ -670,9 +681,15 @@

   */

  priv = netdev_priv(dev);

  memset(priv, 0, sizeof(struct snull_priv));

+ priv->dev = dev;
+

  spin_lock_init(&priv->lock);

  snull_rx_ints(dev, 1);  /* enable receive interrupts */

  snull_setup_pool(dev);
+ if (use_napi) {

+  netif_napi_add(dev,&priv->napi,snull_poll,2);

+ }
+

 }
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  linux kernel 驱动