snull是《Linux Device Drivers》中的一個網路驅動的例子。這裡引用這個例子學習Linux網路驅動。 因為snull的源碼,網上已經更新到適合最新內核,而我自己用的還是2.6.22.6比較舊的內核。而網上好像找不到舊版的snull。因此結合《Linux Device Driver ...
snull是《Linux Device Drivers》中的一個網路驅動的例子。這裡引用這個例子學習Linux網路驅動。
因為snull的源碼,網上已經更新到適合最新內核,而我自己用的還是2.6.22.6比較舊的內核。而網上好像找不到舊版的snull。因此結合《Linux Device Drivers》把最新的snull例子移植到2.6.22.6內核中。移植也相對簡單,這裡也提供移植好的代碼。
估計不少網友看到《Linux Device Drivers》的網路驅動部分,一臉懵逼,包括我自己,不理解作者設計這個例子的真正目的,儘管有配圖,仍然懵懂,甚至不知道為什麼會用到6個IP地址。如圖:
其實作者的本意是想通過虛擬網卡來模擬實際的網卡和外部的網路設備的通信來討論網路驅動。通過其中任何一個網路介面(sn0或sn1)發送數據,都在另一個網路介面(sn0或sn1)接收到。
因為sn0和sn1都不在同一個網段,所以sn0和sn1之間直接互ping是不行的,這中間必須必須做點轉換。
例子:
理論上local0和remote0只能互ping,因為他們都在同一個網段:192.168.0.0,但事實上,local0在發出數據之後,local0的第3個位元組最低有效位改取反,就變成了remote1,remote1的數據才能到達local1,因為他們在同一段IP。相反,local1在發出數據之後,local1的第3個位元組最低有效位改取反,就變成了remote0,remote0的數據才能到達local0.
因此,在實驗之前,需要添加一些配置:
在/etc/networks文件中添加如下網段IP:
snullnet0 192.168.2.0
snullnet1 192.168.3.0
在/etc/hosts文件中添加如下IP地址
192.168.2.8 local0
192.168.2.9 remote0
192.168.3.9 local1
192.168.3.8 remote1
註意: 1. 網段IP和IP地址的第三個位元組的最低有效位是相反的
2. local0和remote1第四個位元組必須一樣,remote0和local1第四個位元組必須一樣
3. 如果開發板上的真正網卡用了的網段IP,就不能再用於本實驗。如:我的開發板的DM9000網卡使用網段是192.168.1.0, 因此本實驗不能再使用192.168.1.0作為網段,否則有衝突。
代碼: snull.c, 其中snull.h沒改動,因此不貼出來
1 /* 2 * snull.c -- the Simple Network Utility 3 * 4 * Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet 5 * Copyright (C) 2001 O'Reilly & Associates 6 * 7 * The source code in this file can be freely used, adapted, 8 * and redistributed in source or binary form, so long as an 9 * acknowledgment appears in derived source files. The citation 10 * should list that the code comes from the book "Linux Device 11 * Drivers" by Alessandro Rubini and Jonathan Corbet, published 12 * by O'Reilly & Associates. No warranty is attached; 13 * we cannot take responsibility for errors or fitness for use. 14 * 15 * $Id: snull.c,v 1.21 2004/11/05 02:36:03 rubini Exp $ 16 */ 17 18 #include <linux/module.h> 19 #include <linux/init.h> 20 #include <linux/moduleparam.h> 21 22 #include <linux/sched.h> 23 #include <linux/kernel.h> /* printk() */ 24 #include <linux/slab.h> /* kmalloc() */ 25 #include <linux/errno.h> /* error codes */ 26 #include <linux/types.h> /* size_t */ 27 #include <linux/interrupt.h> /* mark_bh */ 28 29 #include <linux/in.h> 30 #include <linux/netdevice.h> /* struct device, and other headers */ 31 #include <linux/etherdevice.h> /* eth_type_trans */ 32 #include <linux/ip.h> /* struct iphdr */ 33 #include <linux/tcp.h> /* struct tcphdr */ 34 #include <linux/skbuff.h> 35 36 #include "snull.h" 37 38 #include <linux/in6.h> 39 #include <asm/checksum.h> 40 41 MODULE_AUTHOR("Alessandro Rubini, Jonathan Corbet"); 42 MODULE_LICENSE("Dual BSD/GPL"); 43 44 45 /* 46 * Transmitter lockup simulation, normally disabled. 47 */ 48 static int lockup = 0; 49 module_param(lockup, int, 0); 50 51 static int timeout = SNULL_TIMEOUT; 52 module_param(timeout, int, 0); 53 54 /* 55 * Do we run in NAPI mode? 56 */ 57 static int use_napi = 0; 58 module_param(use_napi, int, 0); 59 60 61 /* 62 * A structure representing an in-flight packet. 63 */ 64 struct snull_packet { 65 struct snull_packet *next; 66 struct net_device *dev; 67 int datalen; 68 u8 data[ETH_DATA_LEN]; 69 }; 70 71 int pool_size = 8; 72 module_param(pool_size, int, 0); 73 74 /* 75 * This structure is private to each device. It is used to pass 76 * packets in and out, so there is place for a packet 77 */ 78 79 struct snull_priv { 80 struct net_device_stats stats; 81 int status; 82 struct snull_packet *ppool; 83 struct snull_packet *rx_queue; /* List of incoming packets */ 84 int rx_int_enabled; 85 int tx_packetlen; 86 u8 *tx_packetdata; 87 struct sk_buff *skb; 88 spinlock_t lock; 89 struct net_device *dev; 90 //struct napi_struct napi; 91 }; 92 93 static void snull_tx_timeout(struct net_device *dev); 94 static void (*snull_interrupt)(int, void *, struct pt_regs *); 95 96 /* 97 * Set up a device's packet pool. 98 */ 99 void snull_setup_pool(struct net_device *dev) 100 { 101 struct snull_priv *priv = netdev_priv(dev); 102 int i; 103 struct snull_packet *pkt; 104 105 priv->ppool = NULL; 106 for (i = 0; i < pool_size; i++) { 107 pkt = kmalloc (sizeof (struct snull_packet), GFP_KERNEL); 108 if (pkt == NULL) { 109 printk (KERN_NOTICE "Ran out of memory allocating packet pool\n"); 110 return; 111 } 112 pkt->dev = dev; 113 pkt->next = priv->ppool; 114 priv->ppool = pkt; 115 } 116 } 117 118 void snull_teardown_pool(struct net_device *dev) 119 { 120 struct snull_priv *priv = netdev_priv(dev); 121 struct snull_packet *pkt; 122 123 while ((pkt = priv->ppool)) { 124 priv->ppool = pkt->next; 125 kfree (pkt); 126 /* FIXME - in-flight packets ? */ 127 } 128 } 129 130 /* 131 * Buffer/pool management. 132 */ 133 struct snull_packet *snull_get_tx_buffer(struct net_device *dev) 134 { 135 struct snull_priv *priv = netdev_priv(dev); 136 unsigned long flags; 137 struct snull_packet *pkt; 138 139 spin_lock_irqsave(&priv->lock, flags); 140 pkt = priv->ppool; 141 priv->ppool = pkt->next; 142 if (priv->ppool == NULL) { 143 printk (KERN_INFO "Pool empty\n"); 144 netif_stop_queue(dev); 145 } 146 spin_unlock_irqrestore(&priv->lock, flags); 147 return pkt; 148 } 149 150 151 void snull_release_buffer(struct snull_packet *pkt) 152 { 153 unsigned long flags; 154 struct snull_priv *priv = netdev_priv(pkt->dev); 155 156 spin_lock_irqsave(&priv->lock, flags); 157 pkt->next = priv->ppool; 158 priv->ppool = pkt; 159 spin_unlock_irqrestore(&priv->lock, flags); 160 if (netif_queue_stopped(pkt->dev) && pkt->next == NULL) 161 netif_wake_queue(pkt->dev); 162 163 printk("snull_release_buffer\n"); 164 } 165 166 void snull_enqueue_buf(struct net_device *dev, struct snull_packet *pkt) 167 { 168 unsigned long flags; 169 struct snull_priv *priv = netdev_priv(dev); 170 171 spin_lock_irqsave(&priv->lock, flags); 172 pkt->next = priv->rx_queue; /* FIXME - misorders packets */ 173 priv->rx_queue = pkt; 174 spin_unlock_irqrestore(&priv->lock, flags); 175 } 176 177 struct snull_packet *snull_dequeue_buf(struct net_device *dev) 178 { 179 struct snull_priv *priv = netdev_priv(dev); 180 struct snull_packet *pkt; 181 unsigned long flags; 182 183 spin_lock_irqsave(&priv->lock, flags); 184 pkt = priv->rx_queue; 185 if (pkt != NULL) 186 priv->rx_queue = pkt->next; 187 spin_unlock_irqrestore(&priv->lock, flags); 188 return pkt; 189 } 190 191 /* 192 * Enable and disable receive interrupts. 193 */ 194 static void snull_rx_ints(struct net_device *dev, int enable) 195 { 196 struct snull_priv *priv = netdev_priv(dev); 197 priv->rx_int_enabled = enable; 198 } 199 200 201 /* 202 * Open and close 203 */ 204 205 int snull_open(struct net_device *dev) 206 { 207 /* request_region(), request_irq(), .... (like fops->open) */ 208 209 /* 210 * Assign the hardware address of the board: use "\0SNULx", where 211 * x is 0 or 1. The first byte is '\0' to avoid being a multicast 212 * address (the first byte of multicast addrs is odd). 213 */ 214 /* [cgw]: 分配一個假的硬體地址,真正的網卡的時候,這個地址是從網卡讀出來的 */ 215 memcpy(dev->dev_addr, "\0SNUL0", ETH_ALEN); 216 /* [cgw]: 因為註冊了兩個虛擬網卡,第二個虛擬網卡的地址跟第一個的地址必須不一樣 217 * 即這兩個網卡地址分別為\0SNUL0和\0SNUL1 218 */ 219 if (dev == snull_devs[1]) 220 dev->dev_addr[ETH_ALEN-1]++; /* \0SNUL1 */ 221 /* [cgw]: 啟動發送隊列 */ 222 netif_start_queue(dev); 223 224 printk("snull_open\n"); 225 226 return 0; 227 } 228 229 int snull_release(struct net_device *dev) 230 { 231 /* release ports, irq and such -- like fops->close */ 232 233 netif_stop_queue(dev); /* can't transmit any more */ 234 235 printk("snull_release\n"); 236 237 return 0; 238 } 239 240 /* 241 * Configuration changes (passed on by ifconfig) 242 */ 243 int snull_config(struct net_device *dev, struct ifmap *map) 244 { 245 if (dev->flags & IFF_UP) /* can't act on a running interface */ 246 return -EBUSY; 247 248 /* Don't allow changing the I/O address */ 249 if (map->base_addr != dev->base_addr) { 250 printk(KERN_WARNING "snull: Can't change I/O address\n"); 251 return -EOPNOTSUPP; 252 } 253 254 /* Allow changing the IRQ */ 255 if (map->irq != dev->irq) { 256 dev->irq = map->irq; 257 /* request_irq() is delayed to open-time */ 258 } 259 260 printk("snull_config\n"); 261 262 /* ignore other fields */ 263 return 0; 264 } 265 266 /* 267 * Receive a packet: retrieve, encapsulate and pass over to upper levels 268 */ 269 void snull_rx(struct net_device *dev, struct snull_packet *pkt) 270 { 271 struct sk_buff *skb; 272 struct snull_priv *priv = netdev_priv(dev); 273 274 /* 275 * The packet has been retrieved from the transmission 276 * medium. Build an skb around it, so upper layers can handle it 277 */ 278 /* [cgw]: 為接收包分配一個skb */ 279 skb = dev_alloc_skb(pkt->datalen + 2); 280 if (!skb) { 281 if (printk_ratelimit()) 282 printk(KERN_NOTICE "snull rx: low on mem - packet dropped\n"); 283 priv->stats.rx_dropped++; 284 goto out; 285 } 286 /* [cgw]: 16位元組對齊,即IP首部前是網卡硬體地址首部,其占14位元組,需要為其增加2 287 * 個位元組 288 */ 289 skb_reserve(skb, 2); /* align IP on 16B boundary */ 290 /* [cgw]: 開闢一個數據緩衝區用於存放接收數據 */ 291 memcpy(skb_put(skb, pkt->datalen), pkt->data, pkt->datalen); 292 293 /* Write metadata, and then pass to the receive level */ 294 skb->dev = dev; 295 if (skb->dev == snull_devs[0]) { 296 printk("skb->dev is snull_devs[0]\n"); 297 } else { 298 printk("skb->dev is snull_devs[1]\n"); 299 } 300 /* [cgw]: 確定包的協議ID */ 301 skb->protocol = eth_type_trans(skb, dev); 302 303 printk("skb->protocol = %d\n", skb->protocol); 304 305 skb->ip_summed = CHECKSUM_UNNECESSARY; /* don't check it */ 306 /* [cgw]: 統計接收包數和位元組數 */ 307 priv->stats.rx_packets++; 308 priv->stats.rx_bytes += pkt->datalen; 309 /* [cgw]: 上報應用層 */ 310 netif_rx(skb); 311 312 printk("snull_rx\n"); 313 314 out: 315 return; 316 } 317 318 319 /* 320 * The poll implementation. 321 */ 322 //static int snull_poll(struct napi_struct *napi, int budget) 323 static int snull_poll(struct net_device *dev, int *budget) 324 { 325 //int npackets = 0; 326 //struct sk_buff *skb; 327 //struct snull_priv *priv = container_of(napi, struct snull_priv, napi); 328 //struct net_device *dev = priv->dev; 329 //struct snull_packet *pkt; 330 331 int npackets = 0, quota = min(dev->quota, *budget); 332 struct sk_buff *skb; 333 struct snull_priv *priv = netdev_priv(dev); 334 struct snull_packet *pkt; 335 336 printk("snull_poll\n"); 337 338 //while (npackets < budget && priv->rx_queue) { 339 while (npackets < quota && priv->rx_queue) { 340 pkt = snull_dequeue_buf(dev); 341 skb = dev_alloc_skb(pkt->datalen + 2); 342 if (! skb) { 343 if (printk_ratelimit()) 344 printk(KERN_NOTICE "snull: packet dropped\n"); 345 priv->stats.rx_dropped++; 346 snull_release_buffer(pkt); 347 continue; 348 } 349 skb_reserve(skb, 2); /* align IP on 16B boundary */ 350 memcpy(skb_put(skb, pkt->datalen), pkt->data, pkt->datalen); 351 skb->dev = dev; 352 skb->protocol = eth_type_trans(skb, dev); 353 skb->ip_summed = CHECKSUM_UNNECESSARY; /* don't check it */ 354 netif_receive_skb(skb); 355 356 /* Maintain stats */ 357 npackets++; 358 priv->stats.rx_packets++; 359 priv->stats.rx_bytes += pkt->datalen; 360 snull_release_buffer(pkt); 361 } 362 /* If we processed all packets, we're done; tell the kernel and reenable ints */ 363 *budget -= npackets; 364 dev->quota -= npackets; 365 if (! priv->rx_queue) { 366 //napi_complete(napi); 367 netif_rx_complete(dev); 368 snull_rx_ints(dev, 1); 369 return 0; 370 } 371 /* We couldn't process everything. */ 372 //return npackets; 373 return 1; 374 } 375 376 /* 377 * The typical interrupt entry point 378 */ 379 static void snull_regular_interrupt(int irq, void *dev_id, struct pt_regs *regs) 380 { 381 int statusword; 382 struct snull_priv *priv; 383 struct snull_packet *pkt = NULL; 384 /* 385 * As usual, check the "device" pointer to be sure it is 386 * really interrupting. 387 * Then assign "struct device *dev" 388 */ 389 struct net_device *dev = (struct net_device *)dev_id; 390 /* ... and check with hw if it's really ours */ 391 392 /* paranoid */ 393 if (!dev) 394 return; 395 396 /* Lock the device */ 397 priv = netdev_priv(dev); 398 spin_lock(&priv->lock); 399 400 /* [cgw]: 判斷產生的是什麼類型的中斷,接收還是中斷 */ 401 /* retrieve statusword: real netdevices use I/O instructions */ 402 statusword = priv->status; 403 404 printk("priv->status = %d\n", priv->status); 405 406 priv->status = 0; 407 /* [cgw]: 接收完成中斷 */ 408 if (statusword & SNULL_RX_INTR) { 409 /* send it to snull_rx for handling */ 410 pkt = priv->rx_queue; 411 if (pkt) { 412 priv->rx_queue = pkt->next; 413 /* [cgw]: 網卡接收到數據,上報給應用層 */ 414 snull_rx(dev, pkt); 415 } 416 } 417 /* [cgw]: 發送完成中斷 */ 418 if (statusword & SNULL_TX_INTR) { 419 /* [cgw]: 統計已發送的包數和總位元組數,並釋放這個包的記憶體 */ 420 /* a transmission is over: free the skb */ 421 priv->stats.tx_packets++; 422 priv->stats.tx_bytes += priv->tx_packetlen; 423 dev_kfree_skb(priv->skb); 424 } 425 426 /* Unlock the device and we are done */ 427 spin_unlock(&priv->lock); 428 if (pkt) snull_release_buffer(pkt); /* Do this outside the lock! */ 429 430 printk("snull_regular_interrupt\n"); 431 432 return; 433 } 434 435 /* 436 * A NAPI interrupt handler. 437 */ 438 static void snull_napi_interrupt(int irq, void *dev_id, struct pt_regs *regs) 439 { 440 int statusword; 441 struct snull_priv *priv; 442 443 /* 444 * As usual, check the "device" pointer for shared handlers. 445 * Then assign "struct device *dev" 446 */ 447 struct net_device *dev = (struct net_device *)dev_id; 448 /* ... and check with hw if it's really ours */ 449 450 printk("snull_napi_interrupt\n"); 451 452 /* paranoid */ 453 if (!dev) 454 return; 455 456 /* Lock the device */ 457 priv = netdev_priv(dev); 458 spin_lock(&priv->lock); 459 460 /* retrieve statusword: real netdevices use I/O instructions */ 461 statusword = priv->status; 462 priv->status = 0; 463 if (statusword & SNULL_RX_INTR) { 464 snull_rx_ints(dev, 0); /* Disable further interrupts */ 465 //napi_schedule(&priv->napi); 466 netif_rx_schedule(dev); 467 } 468 if (statusword & SNULL_TX_INTR) { 469 /* a transmission is over: free the skb */ 470 priv->stats.tx_packets++; 471 priv->stats.tx_bytes += priv->tx_packetlen; 472 dev_kfree_skb(priv->skb); 473 } 474 475 /* Unlock the device and we are done */ 476 spin_unlock(&priv->lock); 477 return; 478 } 479 480 481 /* 482 * Transmit a packet (low level interface) 483 */ 484 static void snull_hw_tx(char *buf, int len, struct net_device *dev) 485 { 486 /* 487 * This function deals with hw details. This interface loops 488 * back the packet to the other snull interface (if any). 489 * In other words, this function implements the snull behaviour, 490 * while all other procedures are rather device-independent 491 */ 492 struct iphdr *ih; 493 struct net_device *dest; 494 struct snull_priv *priv; 495 u32 *saddr, *daddr; 496 struct snull_packet *tx_buffer; 497