Linux Device Driver(3rd version)的第17章已经解释的很详细了,大家可以参考,当然,在2.6.24之后的内核中,使用了N-NAPI,所以书中第17章的程序snull是无法在2.6.24内核中编译通过的,下面是我根据2.6.24内核所作的patch:
--- /home/heyunqi/examples/snull/snull.c 2005-02-01 04:31:02.000000000 +0800
+++ snull.c 2008-08-05 18:12:47.000000000 +0800
@@ -15,7 +15,6 @@
* $Id: snull.c,v 1.21 2004/11/05 02:36:03 rubini Exp $
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/moduleparam.h>
@@ -87,6 +86,8 @@
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 +285,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 +317,10 @@
snull_release_buffer(pkt);
}
/* If we processed all packets, we're done; tell the kernel and reenable ints */
- *budget -= npackets;
- dev->quota -= npackets;
+ budget -= npackets;
+ //dev->quota -= npackets;
if (! priv->rx_queue) {
- netif_rx_complete(dev);
+ netif_rx_complete(dev,napi);
snull_rx_ints(dev, 1);
return 0;
}
@@ -403,7 +405,7 @@
priv->status = 0;
if (statusword & SNULL_RX_INTR) {
snull_rx_ints(dev, 0); /* Disable further interrupts */
- netif_rx_schedule(dev);
+ netif_rx_schedule(dev,&priv->napi);
}
if (statusword & SNULL_TX_INTR) {
/* a transmission is over: free the skb */
@@ -572,33 +574,6 @@
* This function is called to fill up an eth header, since arp is not
* available on the interface
*/
-int snull_rebuild_header(struct sk_buff *skb)
-{
- struct ethhdr *eth = (struct ethhdr *) skb->data;
- struct net_device *dev = skb->dev;
-
- memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
- memcpy(eth->h_dest, dev->dev_addr, dev->addr_len);
- eth->h_dest[ETH_ALEN-1] ^= 0x01; /* dest is us xor 1 */
- return 0;
-}
-
-
-int snull_header(struct sk_buff *skb, struct net_device *dev,
- unsigned short type, void *daddr, void *saddr,
- unsigned int len)
-{
- struct ethhdr *eth = (struct ethhdr *)skb_push(skb,ETH_HLEN);
-
- eth->h_proto = htons(type);
- memcpy(eth->h_source, saddr ? saddr : dev->dev_addr, dev->addr_len);
- memcpy(eth->h_dest, daddr ? daddr : dev->dev_addr, dev->addr_len);
- eth->h_dest[ETH_ALEN-1] ^= 0x01; /* dest is us xor 1 */
- return (dev->hard_header_len);
-}
-
-
-
/*
@@ -651,18 +626,11 @@
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->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
@@ -707,16 +675,24 @@
int snull_init_module(void)
{
int result, i, ret = -ENOMEM;
+ struct snull_priv* priv;
snull_interrupt = use_napi ? snull_napi_interrupt : snull_regular_interrupt;
/* Allocate the devices */
+ /* Allocate the devices */
snull_devs[0] = alloc_netdev(sizeof(struct snull_priv), "sn%d",
snull_init);
snull_devs[1] = alloc_netdev(sizeof(struct snull_priv), "sn%d",
snull_init);
if (snull_devs[0] == NULL || snull_devs[1] == NULL)
goto out;
+ priv = netdev_priv(snull_devs[0]);
+ priv->dev = snull_devs[0];
+ netif_napi_add(priv->dev, &priv->napi, snull_poll, 64);
+ priv = netdev_priv(snull_devs[1]);
+ priv->dev = snull_devs[1];
+ netif_napi_add(priv->dev, &priv->napi, snull_poll, 64);
ret = -ENODEV;
for (i = 0; i < 2; i++)