upgrade to linux 2.6.10-1.12_FC2
[linux-2.6.git] / net / core / pktgen.c
1 /* -*-linux-c-*-
2  * $Id: pktgen.c,v 1.8 2002/07/15 19:30:17 robert Exp $
3  * pktgen.c: Packet Generator for performance evaluation.
4  *
5  * Copyright 2001, 2002 by Robert Olsson <robert.olsson@its.uu.se>
6  *                               Uppsala University, Sweden
7  *
8  * A tool for loading the network with preconfigurated packets.
9  * The tool is implemented as a linux module.  Parameters are output 
10  * device, IPG (interpacket gap), number of packets, and whether
11  * to use multiple SKBs or just the same one.
12  * pktgen uses the installed interface's output routine.
13  *
14  * Additional hacking by:
15  *
16  * Jens.Laas@data.slu.se
17  * Improved by ANK. 010120.
18  * Improved by ANK even more. 010212.
19  * MAC address typo fixed. 010417 --ro
20  * Integrated.  020301 --DaveM
21  * Added multiskb option 020301 --DaveM
22  * Scaling of results. 020417--sigurdur@linpro.no
23  * Significant re-work of the module:
24  *   *  Updated to support generation over multiple interfaces at once
25  *       by creating 32 /proc/net/pg* files.  Each file can be manipulated
26  *       individually.
27  *   *  Converted many counters to __u64 to allow longer runs.
28  *   *  Allow configuration of ranges, like min/max IP address, MACs,
29  *       and UDP-ports, for both source and destination, and can
30  *       set to use a random distribution or sequentially walk the range.
31  *   *  Can now change some values after starting.
32  *   *  Place 12-byte packet in UDP payload with magic number,
33  *       sequence number, and timestamp.  Will write receiver next.
34  *   *  The new changes seem to have a performance impact of around 1%,
35  *       as far as I can tell.
36  *   --Ben Greear <greearb@candelatech.com>
37  * Integrated to 2.5.x 021029 --Lucio Maciel (luciomaciel@zipmail.com.br)
38  *
39  * Renamed multiskb to clone_skb and cleaned up sending core for two distinct 
40  * skb modes. A clone_skb=0 mode for Ben "ranges" work and a clone_skb != 0 
41  * as a "fastpath" with a configurable number of clones after alloc's.
42  *
43  * clone_skb=0 means all packets are allocated this also means ranges time 
44  * stamps etc can be used. clone_skb=100 means 1 malloc is followed by 100 
45  * clones.
46  *
47  * Also moved to /proc/net/pktgen/ 
48  * --ro 
49  *
50  * Fix refcount off by one if first packet fails, potential null deref, 
51  * memleak 030710- KJP
52  *
53  * Fixed unaligned access on IA-64 Grant Grundler <grundler@parisc-linux.org>
54  *
55  * New xmit() return, do_div and misc clean up by Stephen Hemminger 
56  * <shemminger@osdl.org> 040923
57  *
58  * See Documentation/networking/pktgen.txt for how to use this.
59  */
60
61 #include <linux/module.h>
62 #include <linux/moduleparam.h>
63 #include <linux/kernel.h>
64 #include <linux/sched.h>
65 #include <linux/types.h>
66 #include <linux/string.h>
67 #include <linux/ptrace.h>
68 #include <linux/errno.h>
69 #include <linux/ioport.h>
70 #include <linux/slab.h>
71 #include <linux/interrupt.h>
72 #include <linux/delay.h>
73 #include <linux/init.h>
74 #include <linux/inet.h>
75 #include <linux/rcupdate.h>
76 #include <linux/bitops.h>
77 #include <asm/byteorder.h>
78 #include <asm/io.h>
79 #include <asm/dma.h>
80 #include <asm/uaccess.h>
81
82 #include <linux/in.h>
83 #include <linux/ip.h>
84 #include <linux/udp.h>
85 #include <linux/skbuff.h>
86 #include <linux/netdevice.h>
87 #include <linux/inetdevice.h>
88 #include <linux/rtnetlink.h>
89 #include <linux/proc_fs.h>
90 #include <linux/if_arp.h>
91 #include <net/checksum.h>
92 #include <asm/timex.h>
93
94 #define cycles()        ((u32)get_cycles())
95
96
97 #define VERSION "pktgen version 1.32"
98 static char version[] __initdata = 
99   "pktgen.c: v1.4: Packet Generator for packet performance testing.\n";
100
101 /* Used to help with determining the pkts on receive */
102
103 #define PKTGEN_MAGIC 0xbe9be955
104
105
106 /* Keep information per interface */
107 struct pktgen_info {
108         /* Parameters */
109
110         /* If min != max, then we will either do a linear iteration, or
111          * we will do a random selection from within the range.
112          */
113         __u32 flags;     
114
115 #define F_IPSRC_RND   (1<<0)  /* IP-Src Random  */
116 #define F_IPDST_RND   (1<<1)  /* IP-Dst Random  */
117 #define F_UDPSRC_RND  (1<<2)  /* UDP-Src Random */
118 #define F_UDPDST_RND  (1<<3)  /* UDP-Dst Random */
119 #define F_MACSRC_RND  (1<<4)  /* MAC-Src Random */
120 #define F_MACDST_RND  (1<<5)  /* MAC-Dst Random */
121 #define F_SET_SRCMAC  (1<<6)  /* Specify-Src-Mac 
122                                  (default is to use Interface's MAC Addr) */
123 #define F_SET_SRCIP   (1<<7)  /*  Specify-Src-IP
124                                   (default is to use Interface's IP Addr) */ 
125
126         
127         int pkt_size;    /* = ETH_ZLEN; */
128         int nfrags;
129         __u32 ipg;       /* Default Interpacket gap in nsec */
130         __u64 count;     /* Default No packets to send */
131         __u64 sofar;     /* How many pkts we've sent so far */
132         __u64 errors;    /* Errors when trying to transmit, pkts will be re-sent */
133         struct timeval started_at;
134         struct timeval stopped_at;
135         __u64 idle_acc;
136         __u32 seq_num;
137         
138         int clone_skb;   /* Use multiple SKBs during packet gen.  If this number
139                           * is greater than 1, then that many coppies of the same
140                           * packet will be sent before a new packet is allocated.
141                           * For instance, if you want to send 1024 identical packets
142                           * before creating a new packet, set clone_skb to 1024.
143                           */
144         int busy;
145         int do_run_run;   /* if this changes to false, the test will stop */
146         
147         char outdev[32];
148         char dst_min[32];
149         char dst_max[32];
150         char src_min[32];
151         char src_max[32];
152
153         /* If we're doing ranges, random or incremental, then this
154          * defines the min/max for those ranges.
155          */
156         __u32 saddr_min; /* inclusive, source IP address */
157         __u32 saddr_max; /* exclusive, source IP address */
158         __u32 daddr_min; /* inclusive, dest IP address */
159         __u32 daddr_max; /* exclusive, dest IP address */
160
161         __u16 udp_src_min; /* inclusive, source UDP port */
162         __u16 udp_src_max; /* exclusive, source UDP port */
163         __u16 udp_dst_min; /* inclusive, dest UDP port */
164         __u16 udp_dst_max; /* exclusive, dest UDP port */
165
166         __u32 src_mac_count; /* How many MACs to iterate through */
167         __u32 dst_mac_count; /* How many MACs to iterate through */
168         
169         unsigned char dst_mac[6];
170         unsigned char src_mac[6];
171         
172         __u32 cur_dst_mac_offset;
173         __u32 cur_src_mac_offset;
174         __u32 cur_saddr;
175         __u32 cur_daddr;
176         __u16 cur_udp_dst;
177         __u16 cur_udp_src;
178         
179         __u8 hh[14];
180         /* = { 
181            0x00, 0x80, 0xC8, 0x79, 0xB3, 0xCB, 
182            
183            We fill in SRC address later
184            0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
185            0x08, 0x00
186            };
187         */
188         __u16 pad; /* pad out the hh struct to an even 16 bytes */
189         char result[512];
190
191         /* proc file names */
192         char fname[80];
193         char busy_fname[80];
194         
195         struct proc_dir_entry *proc_ent;
196         struct proc_dir_entry *busy_proc_ent;
197 };
198
199 struct pktgen_hdr {
200         __u32 pgh_magic;
201         __u32 seq_num;
202         __u32 tv_sec;
203         __u32 tv_usec;
204 };
205
206 static int cpu_speed;
207 static int debug;
208
209 /* Module parameters, defaults. */
210 static int count_d = 100000;
211 static int ipg_d;
212 static int clone_skb_d;
213
214
215 #define MAX_PKTGEN 8
216 static struct pktgen_info pginfos[MAX_PKTGEN];
217
218
219 /** Convert to miliseconds */
220 static inline __u64 tv_to_ms(const struct timeval* tv) {
221         __u64 ms = tv->tv_usec / 1000;
222         ms += (__u64)tv->tv_sec * (__u64)1000;
223         return ms;
224 }
225
226 static inline __u64 getCurMs(void) {
227         struct timeval tv;
228         do_gettimeofday(&tv);
229         return tv_to_ms(&tv);
230 }
231
232 #define PG_PROC_DIR "pktgen"
233 static struct proc_dir_entry *proc_dir;
234
235 static struct net_device *setup_inject(struct pktgen_info* info)
236 {
237         struct net_device *odev;
238
239         odev = dev_get_by_name(info->outdev);
240         if (!odev) {
241                 sprintf(info->result, "No such netdevice: \"%s\"", info->outdev);
242                 goto out;
243         }
244
245         if (odev->type != ARPHRD_ETHER) {
246                 sprintf(info->result, "Not ethernet device: \"%s\"", info->outdev);
247                 goto out_put;
248         }
249
250         if (!netif_running(odev)) {
251                 sprintf(info->result, "Device is down: \"%s\"", info->outdev);
252                 goto out_put;
253         }
254
255         /* Default to the interface's mac if not explicitly set. */
256         if (!(info->flags & F_SET_SRCMAC)) {
257                 memcpy(&(info->hh[6]), odev->dev_addr, 6);
258         }
259         else {
260                 memcpy(&(info->hh[6]), info->src_mac, 6);
261         }
262
263         /* Set up Dest MAC */
264         memcpy(&(info->hh[0]), info->dst_mac, 6);
265         
266         info->saddr_min = 0;
267         info->saddr_max = 0;
268         if (strlen(info->src_min) == 0) {
269                 struct in_device *in_dev;
270
271                 rcu_read_lock();
272                 in_dev = __in_dev_get(odev);
273                 if (in_dev) {
274                         if (in_dev->ifa_list) {
275                                 info->saddr_min = in_dev->ifa_list->ifa_address;
276                                 info->saddr_max = info->saddr_min;
277                         }
278                 }
279                 rcu_read_unlock();
280         }
281         else {
282                 info->saddr_min = in_aton(info->src_min);
283                 info->saddr_max = in_aton(info->src_max);
284         }
285
286         info->daddr_min = in_aton(info->dst_min);
287         info->daddr_max = in_aton(info->dst_max);
288
289         /* Initialize current values. */
290         info->cur_dst_mac_offset = 0;
291         info->cur_src_mac_offset = 0;
292         info->cur_saddr = info->saddr_min;
293         info->cur_daddr = info->daddr_min;
294         info->cur_udp_dst = info->udp_dst_min;
295         info->cur_udp_src = info->udp_src_min;
296         
297         return odev;
298
299 out_put:
300         dev_put(odev);
301 out:
302         return NULL;
303 }
304
305 static void nanospin(int ipg, struct pktgen_info* info)
306 {
307         u32 idle_start, idle;
308
309         idle_start = cycles();
310
311         for (;;) {
312                 barrier();
313                 idle = cycles() - idle_start;
314                 if (idle * 1000 >= ipg * cpu_speed)
315                         break;
316         }
317         info->idle_acc += idle;
318 }
319
320 static int calc_mhz(void)
321 {
322         struct timeval start, stop;
323         u32 start_s, elapsed;
324
325         do_gettimeofday(&start);
326         start_s = cycles();
327         do {
328                 barrier();
329                 elapsed = cycles() - start_s;
330                 if (elapsed == 0)
331                         return 0;
332         } while (elapsed < 1000 * 50000);
333         do_gettimeofday(&stop);
334         return elapsed/(stop.tv_usec-start.tv_usec+1000000*(stop.tv_sec-start.tv_sec));
335 }
336
337 static void cycles_calibrate(void)
338 {
339         int i;
340
341         for (i = 0; i < 3; i++) {
342                 int res = calc_mhz();
343                 if (res > cpu_speed)
344                         cpu_speed = res;
345         }
346 }
347
348
349 /* Increment/randomize headers according to flags and current values
350  * for IP src/dest, UDP src/dst port, MAC-Addr src/dst
351  */
352 static void mod_cur_headers(struct pktgen_info* info) { 
353         __u32 imn;
354         __u32 imx;
355         
356         /*  Deal with source MAC */
357         if (info->src_mac_count > 1) {
358                 __u32 mc;
359                 __u32 tmp;
360                 if (info->flags & F_MACSRC_RND) {
361                         mc = net_random() % (info->src_mac_count);
362                 }
363                 else {
364                         mc = info->cur_src_mac_offset++;
365                         if (info->cur_src_mac_offset > info->src_mac_count) {
366                                 info->cur_src_mac_offset = 0;
367                         }
368                 }
369
370                 tmp = info->src_mac[5] + (mc & 0xFF);
371                 info->hh[11] = tmp;
372                 tmp = (info->src_mac[4] + ((mc >> 8) & 0xFF) + (tmp >> 8));
373                 info->hh[10] = tmp;
374                 tmp = (info->src_mac[3] + ((mc >> 16) & 0xFF) + (tmp >> 8));
375                 info->hh[9] = tmp;
376                 tmp = (info->src_mac[2] + ((mc >> 24) & 0xFF) + (tmp >> 8));
377                 info->hh[8] = tmp;
378                 tmp = (info->src_mac[1] + (tmp >> 8));
379                 info->hh[7] = tmp;      
380         }
381
382         /*  Deal with Destination MAC */
383         if (info->dst_mac_count > 1) {
384                 __u32 mc;
385                 __u32 tmp;
386                 if (info->flags & F_MACDST_RND) {
387                         mc = net_random() % (info->dst_mac_count);
388                 }
389                 else {
390                         mc = info->cur_dst_mac_offset++;
391                         if (info->cur_dst_mac_offset > info->dst_mac_count) {
392                                 info->cur_dst_mac_offset = 0;
393                         }
394                 }
395
396                 tmp = info->dst_mac[5] + (mc & 0xFF);
397                 info->hh[5] = tmp;
398                 tmp = (info->dst_mac[4] + ((mc >> 8) & 0xFF) + (tmp >> 8));
399                 info->hh[4] = tmp;
400                 tmp = (info->dst_mac[3] + ((mc >> 16) & 0xFF) + (tmp >> 8));
401                 info->hh[3] = tmp;
402                 tmp = (info->dst_mac[2] + ((mc >> 24) & 0xFF) + (tmp >> 8));
403                 info->hh[2] = tmp;
404                 tmp = (info->dst_mac[1] + (tmp >> 8));
405                 info->hh[1] = tmp;      
406         }
407
408         if (info->udp_src_min < info->udp_src_max) {
409                 if (info->flags & F_UDPSRC_RND) {
410                         info->cur_udp_src = ((net_random() % (info->udp_src_max - info->udp_src_min))
411                                              + info->udp_src_min);
412                 }
413                 else {
414                      info->cur_udp_src++;
415                      if (info->cur_udp_src >= info->udp_src_max) {
416                              info->cur_udp_src = info->udp_src_min;
417                      }
418                 }
419         }
420
421         if (info->udp_dst_min < info->udp_dst_max) {
422                 if (info->flags & F_UDPDST_RND) {
423                         info->cur_udp_dst = ((net_random() % (info->udp_dst_max - info->udp_dst_min))
424                                              + info->udp_dst_min);
425                 }
426                 else {
427                      info->cur_udp_dst++;
428                      if (info->cur_udp_dst >= info->udp_dst_max) {
429                              info->cur_udp_dst = info->udp_dst_min;
430                      }
431                 }
432         }
433
434         if ((imn = ntohl(info->saddr_min)) < (imx = ntohl(info->saddr_max))) {
435                 __u32 t;
436                 if (info->flags & F_IPSRC_RND) {
437                         t = ((net_random() % (imx - imn)) + imn);
438                 }
439                 else {
440                      t = ntohl(info->cur_saddr);
441                      t++;
442                      if (t >= imx) {
443                              t = imn;
444                      }
445                 }
446                 info->cur_saddr = htonl(t);
447         }
448
449         if ((imn = ntohl(info->daddr_min)) < (imx = ntohl(info->daddr_max))) {
450                 __u32 t;
451                 if (info->flags & F_IPDST_RND) {
452                         t = ((net_random() % (imx - imn)) + imn);
453                 }
454                 else {
455                      t = ntohl(info->cur_daddr);
456                      t++;
457                      if (t >= imx) {
458                              t = imn;
459                      }
460                 }
461                 info->cur_daddr = htonl(t);
462         }
463 }/* mod_cur_headers */
464
465
466 static struct sk_buff *fill_packet(struct net_device *odev, struct pktgen_info* info)
467 {
468         struct sk_buff *skb = NULL;
469         __u8 *eth;
470         struct udphdr *udph;
471         int datalen, iplen;
472         struct iphdr *iph;
473         struct pktgen_hdr *pgh = NULL;
474         
475         skb = alloc_skb(info->pkt_size + 64 + 16, GFP_ATOMIC);
476         if (!skb) {
477                 sprintf(info->result, "No memory");
478                 return NULL;
479         }
480
481         skb_reserve(skb, 16);
482
483         /*  Reserve for ethernet and IP header  */
484         eth = (__u8 *) skb_push(skb, 14);
485         iph = (struct iphdr *)skb_put(skb, sizeof(struct iphdr));
486         udph = (struct udphdr *)skb_put(skb, sizeof(struct udphdr));
487
488         /* Update any of the values, used when we're incrementing various
489          * fields.
490          */
491         mod_cur_headers(info);
492
493         memcpy(eth, info->hh, 14);
494         
495         datalen = info->pkt_size - 14 - 20 - 8; /* Eth + IPh + UDPh */
496         if (datalen < sizeof(struct pktgen_hdr)) {
497                 datalen = sizeof(struct pktgen_hdr);
498         }
499         
500         udph->source = htons(info->cur_udp_src);
501         udph->dest = htons(info->cur_udp_dst);
502         udph->len = htons(datalen + 8); /* DATA + udphdr */
503         udph->check = 0;  /* No checksum */
504
505         iph->ihl = 5;
506         iph->version = 4;
507         iph->ttl = 3;
508         iph->tos = 0;
509         iph->protocol = IPPROTO_UDP; /* UDP */
510         iph->saddr = info->cur_saddr;
511         iph->daddr = info->cur_daddr;
512         iph->frag_off = 0;
513         iplen = 20 + 8 + datalen;
514         iph->tot_len = htons(iplen);
515         iph->check = 0;
516         iph->check = ip_fast_csum((void *) iph, iph->ihl);
517         skb->protocol = __constant_htons(ETH_P_IP);
518         skb->mac.raw = ((u8 *)iph) - 14;
519         skb->dev = odev;
520         skb->pkt_type = PACKET_HOST;
521
522         if (info->nfrags <= 0) {
523                 pgh = (struct pktgen_hdr *)skb_put(skb, datalen);
524         } else {
525                 int frags = info->nfrags;
526                 int i;
527
528                 /* TODO: Verify this is OK...it sure is ugly. --Ben */
529                 pgh = (struct pktgen_hdr*)(((char*)(udph)) + 8);
530                 
531                 if (frags > MAX_SKB_FRAGS)
532                         frags = MAX_SKB_FRAGS;
533                 if (datalen > frags*PAGE_SIZE) {
534                         skb_put(skb, datalen-frags*PAGE_SIZE);
535                         datalen = frags*PAGE_SIZE;
536                 }
537
538                 i = 0;
539                 while (datalen > 0) {
540                         struct page *page = alloc_pages(GFP_KERNEL, 0);
541                         skb_shinfo(skb)->frags[i].page = page;
542                         skb_shinfo(skb)->frags[i].page_offset = 0;
543                         skb_shinfo(skb)->frags[i].size =
544                                 (datalen < PAGE_SIZE ? datalen : PAGE_SIZE);
545                         datalen -= skb_shinfo(skb)->frags[i].size;
546                         skb->len += skb_shinfo(skb)->frags[i].size;
547                         skb->data_len += skb_shinfo(skb)->frags[i].size;
548                         i++;
549                         skb_shinfo(skb)->nr_frags = i;
550                 }
551
552                 while (i < frags) {
553                         int rem;
554
555                         if (i == 0)
556                                 break;
557
558                         rem = skb_shinfo(skb)->frags[i - 1].size / 2;
559                         if (rem == 0)
560                                 break;
561
562                         skb_shinfo(skb)->frags[i - 1].size -= rem;
563
564                         skb_shinfo(skb)->frags[i] = skb_shinfo(skb)->frags[i - 1];
565                         get_page(skb_shinfo(skb)->frags[i].page);
566                         skb_shinfo(skb)->frags[i].page = skb_shinfo(skb)->frags[i - 1].page;
567                         skb_shinfo(skb)->frags[i].page_offset += skb_shinfo(skb)->frags[i - 1].size;
568                         skb_shinfo(skb)->frags[i].size = rem;
569                         i++;
570                         skb_shinfo(skb)->nr_frags = i;
571                 }
572         }
573
574         /* Stamp the time, and sequence number, convert them to network byte order */
575         if (pgh) {
576                 struct timeval timestamp;
577
578                 pgh->pgh_magic = htonl(PKTGEN_MAGIC);
579                 pgh->seq_num   = htonl(info->seq_num);
580                 
581                 do_gettimeofday(&timestamp);
582                 pgh->tv_sec    = htonl(timestamp.tv_sec);
583                 pgh->tv_usec   = htonl(timestamp.tv_usec);
584         }
585         
586         return skb;
587 }
588
589 static void show_results(struct pktgen_info* info, int nr_frags)
590 {
591         __u64 total, bps, mbps, pps;
592         unsigned long idle;
593         int size = info->pkt_size + 4; /* incl 32bit ethernet CRC */
594         char *p = info->result;
595
596         total = (info->stopped_at.tv_sec - info->started_at.tv_sec) * 1000000ull
597                 + info->stopped_at.tv_usec - info->started_at.tv_usec;
598
599         BUG_ON(cpu_speed == 0);
600
601         idle = info->idle_acc;
602         do_div(idle, cpu_speed);
603
604         p += sprintf(p, "OK: %llu(c%llu+d%lu) usec, %llu (%dbyte,%dfrags)\n",
605                      (unsigned long long) total,
606                      (unsigned long long) (total - idle), idle,
607                      (unsigned long long) info->sofar,
608                      size, nr_frags);
609
610         pps = info->sofar * USEC_PER_SEC;
611         
612         while ((total >> 32) != 0) {
613                 pps >>= 1;
614                 total >>= 1;
615         }
616
617         do_div(pps, total);
618         
619         bps = pps * 8 * size;
620
621         mbps = bps;
622         do_div(mbps, 1000000);
623         p += sprintf(p, "  %llupps %lluMb/sec (%llubps) errors: %llu",
624                      (unsigned long long) pps,
625                      (unsigned long long) mbps,
626                      (unsigned long long) bps,
627                      (unsigned long long) info->errors);
628 }
629
630 static void inject(struct pktgen_info* info)
631 {
632         struct net_device *odev;
633         struct sk_buff *skb = NULL;
634         __u64 lcount = 0;
635         int ret;
636         int last_ok = 1;           /* Was last skb sent? 
637                                     * Or a failed transmit of some sort?  This will keep
638                                     * sequence numbers in order, for example.
639                                     */
640         __u64 fp = 0;
641         __u32 fp_tmp = 0;
642
643         odev = setup_inject(info);
644         if (!odev)
645                 return;
646
647         info->do_run_run = 1; /* Cranke yeself! */
648         info->idle_acc = 0;
649         info->sofar = 0;
650         info->errors = 0;
651         lcount = info->count;
652
653
654         /* Build our initial pkt and place it as a re-try pkt. */
655         skb = fill_packet(odev, info);
656         if (skb == NULL) goto out_reldev;
657
658         do_gettimeofday(&(info->started_at));
659
660         while(info->do_run_run) {
661
662                 /* Set a time-stamp, so build a new pkt each time */
663
664                 if (last_ok) {
665                         if (++fp_tmp >= info->clone_skb ) {
666                                 kfree_skb(skb);
667                                 skb = fill_packet(odev, info);
668                                 if (skb == NULL) {
669                                         goto out_reldev;
670                                 }
671                                 fp++;
672                                 fp_tmp = 0; /* reset counter */
673                         }
674                 }
675
676                 if (!(odev->features & NETIF_F_LLTX))
677                         spin_lock_bh(&odev->xmit_lock);
678                 if (!netif_queue_stopped(odev)) {
679
680                         atomic_inc(&skb->users);
681
682                 retry:
683                         ret = odev->hard_start_xmit(skb, odev);
684                         if (likely(ret == NETDEV_TX_OK)) {
685                                 last_ok = 1;    
686                                 info->sofar++;
687                                 info->seq_num++;
688                         } else if (ret == NETDEV_TX_LOCKED 
689                                    && (odev->features & NETIF_F_LLTX)) {
690                                 cpu_relax();
691                                 goto retry;
692                         } else {
693                                 atomic_dec(&skb->users);
694                                 if (debug && net_ratelimit()) {
695                                    printk(KERN_INFO "Hard xmit error\n");
696                                 }
697                                 info->errors++;
698                                 last_ok = 0;
699                         }
700                 }
701                 else {
702                         /* Re-try it next time */
703                         last_ok = 0;
704                 }
705                 
706                 if (!(odev->features & NETIF_F_LLTX))
707                         spin_unlock_bh(&odev->xmit_lock);
708
709                 if (info->ipg) {
710                         /* Try not to busy-spin if we have larger sleep times.
711                          * TODO:  Investigate better ways to do this.
712                          */
713                         if (info->ipg < 10000) { /* 10 usecs or less */
714                                 nanospin(info->ipg, info);
715                         }
716                         else if (info->ipg < 10000000) { /* 10ms or less */
717                                 udelay(info->ipg / 1000);
718                         }
719                         else {
720                                 mdelay(info->ipg / 1000000);
721                         }
722                 }
723                 
724                 if (signal_pending(current)) {
725                         break;
726                 }
727
728                 /* If lcount is zero, then run forever */
729                 if ((lcount != 0) && (--lcount == 0)) {
730                         if (atomic_read(&skb->users) != 1) {
731                                 u32 idle_start, idle;
732
733                                 idle_start = cycles();
734                                 while (atomic_read(&skb->users) != 1) {
735                                         if (signal_pending(current)) {
736                                                 break;
737                                         }
738                                         schedule();
739                                 }
740                                 idle = cycles() - idle_start;
741                                 info->idle_acc += idle;
742                         }
743                         break;
744                 }
745
746                 if (netif_queue_stopped(odev) || need_resched()) {
747                         u32 idle_start, idle;
748
749                         idle_start = cycles();
750                         do {
751                                 if (signal_pending(current)) {
752                                         info->do_run_run = 0;
753                                         break;
754                                 }
755                                 if (!netif_running(odev)) {
756                                         info->do_run_run = 0;
757                                         break;
758                                 }
759                                 if (need_resched())
760                                         schedule();
761                                 else
762                                         do_softirq();
763                         } while (netif_queue_stopped(odev));
764                         idle = cycles() - idle_start;
765                         info->idle_acc += idle;
766                 }
767         }/* while we should be running */
768
769         do_gettimeofday(&(info->stopped_at));
770
771         show_results(info, skb_shinfo(skb)->nr_frags);
772
773         kfree_skb(skb);
774
775 out_reldev:
776         if (odev) {
777                 dev_put(odev);
778                 odev = NULL;
779         }
780
781         return;
782
783 }
784
785 /* proc/net/pktgen/pg */
786
787 static int proc_busy_read(char *buf , char **start, off_t offset,
788                              int len, int *eof, void *data)
789 {
790         char *p;
791         int idx = (int)(long)(data);
792         struct pktgen_info* info = NULL;
793         
794         if ((idx < 0) || (idx >= MAX_PKTGEN)) {
795                 printk("ERROR: idx: %i is out of range in proc_write\n", idx);
796                 return -EINVAL;
797         }
798         info = &(pginfos[idx]);
799   
800         p = buf;
801         p += sprintf(p, "%d\n", info->busy);
802         *eof = 1;
803   
804         return p-buf;
805 }
806
807 static int proc_read(char *buf , char **start, off_t offset,
808                         int len, int *eof, void *data)
809 {
810         char *p;
811         int i;
812         int idx = (int)(long)(data);
813         struct pktgen_info* info = NULL;
814         __u64 sa;
815         __u64 stopped;
816         __u64 now = getCurMs();
817         
818         if ((idx < 0) || (idx >= MAX_PKTGEN)) {
819                 printk("ERROR: idx: %i is out of range in proc_write\n", idx);
820                 return -EINVAL;
821         }
822         info = &(pginfos[idx]);
823   
824         p = buf;
825         p += sprintf(p, "%s\n", VERSION); /* Help with parsing compatibility */
826         p += sprintf(p, "Params: count %llu  pkt_size: %u  frags: %d  ipg: %u  clone_skb: %d odev \"%s\"\n",
827                      (unsigned long long) info->count,
828                      info->pkt_size, info->nfrags, info->ipg,
829                      info->clone_skb, info->outdev);
830         p += sprintf(p, "     dst_min: %s  dst_max: %s  src_min: %s  src_max: %s\n",
831                      info->dst_min, info->dst_max, info->src_min, info->src_max);
832         p += sprintf(p, "     src_mac: ");
833         for (i = 0; i < 6; i++) {
834                 p += sprintf(p, "%02X%s", info->src_mac[i], i == 5 ? "  " : ":");
835         }
836         p += sprintf(p, "dst_mac: ");
837         for (i = 0; i < 6; i++) {
838                 p += sprintf(p, "%02X%s", info->dst_mac[i], i == 5 ? "\n" : ":");
839         }
840         p += sprintf(p, "     udp_src_min: %d  udp_src_max: %d  udp_dst_min: %d  udp_dst_max: %d\n",
841                      info->udp_src_min, info->udp_src_max, info->udp_dst_min,
842                      info->udp_dst_max);
843         p += sprintf(p, "     src_mac_count: %d  dst_mac_count: %d\n     Flags: ",
844                      info->src_mac_count, info->dst_mac_count);
845         if (info->flags &  F_IPSRC_RND) {
846                 p += sprintf(p, "IPSRC_RND  ");
847         }
848         if (info->flags & F_IPDST_RND) {
849                 p += sprintf(p, "IPDST_RND  ");
850         }
851         if (info->flags & F_UDPSRC_RND) {
852                 p += sprintf(p, "UDPSRC_RND  ");
853         }
854         if (info->flags & F_UDPDST_RND) {
855                 p += sprintf(p, "UDPDST_RND  ");
856         }
857         if (info->flags & F_MACSRC_RND) {
858                 p += sprintf(p, "MACSRC_RND  ");
859         }
860         if (info->flags & F_MACDST_RND) {
861                 p += sprintf(p, "MACDST_RND  ");
862         }
863         p += sprintf(p, "\n");
864         
865         sa = tv_to_ms(&(info->started_at));
866         stopped = tv_to_ms(&(info->stopped_at));
867         if (info->do_run_run) {
868                 stopped = now; /* not really stopped, more like last-running-at */
869         }
870         p += sprintf(p, "Current:\n     pkts-sofar: %llu  errors: %llu\n     started: %llums  stopped: %llums  now: %llums  idle: %lluns\n",
871                      (unsigned long long) info->sofar,
872                      (unsigned long long) info->errors,
873                      (unsigned long long) sa,
874                      (unsigned long long) stopped,
875                      (unsigned long long) now,
876                      (unsigned long long) info->idle_acc);
877         p += sprintf(p, "     seq_num: %d  cur_dst_mac_offset: %d  cur_src_mac_offset: %d\n",
878                      info->seq_num, info->cur_dst_mac_offset, info->cur_src_mac_offset);
879         p += sprintf(p, "     cur_saddr: 0x%x  cur_daddr: 0x%x  cur_udp_dst: %d  cur_udp_src: %d\n",
880                      info->cur_saddr, info->cur_daddr, info->cur_udp_dst, info->cur_udp_src);
881         
882         if (info->result[0])
883                 p += sprintf(p, "Result: %s\n", info->result);
884         else
885                 p += sprintf(p, "Result: Idle\n");
886         *eof = 1;
887
888         return p - buf;
889 }
890
891 static int count_trail_chars(const char __user *user_buffer, unsigned int maxlen)
892 {
893         int i;
894
895         for (i = 0; i < maxlen; i++) {
896                 char c;
897
898                 if (get_user(c, &user_buffer[i]))
899                         return -EFAULT;
900                 switch (c) {
901                 case '\"':
902                 case '\n':
903                 case '\r':
904                 case '\t':
905                 case ' ':
906                 case '=':
907                         break;
908                 default:
909                         goto done;
910                 };
911         }
912 done:
913         return i;
914 }
915
916 static unsigned long num_arg(const char __user *user_buffer, unsigned long maxlen,
917                              unsigned long *num)
918 {
919         int i = 0;
920
921         *num = 0;
922   
923         for(; i < maxlen; i++) {
924                 char c;
925
926                 if (get_user(c, &user_buffer[i]))
927                         return -EFAULT;
928                 if ((c >= '0') && (c <= '9')) {
929                         *num *= 10;
930                         *num += c -'0';
931                 } else
932                         break;
933         }
934         return i;
935 }
936
937 static int strn_len(const char __user *user_buffer, unsigned int maxlen)
938 {
939         int i = 0;
940
941         for(; i < maxlen; i++) {
942                 char c;
943
944                 if (get_user(c, &user_buffer[i]))
945                         return -EFAULT;
946                 switch (c) {
947                 case '\"':
948                 case '\n':
949                 case '\r':
950                 case '\t':
951                 case ' ':
952                         goto done_str;
953                 default:
954                         break;
955                 };
956         }
957 done_str:
958         return i;
959 }
960
961 static int proc_write(struct file *file, const char __user *user_buffer,
962                          unsigned long count, void *data)
963 {
964         int i = 0, max, len;
965         char name[16], valstr[32];
966         unsigned long value = 0;
967         int idx = (int)(long)(data);
968         struct pktgen_info* info = NULL;
969         char* result = NULL;
970         int tmp;
971         
972         if ((idx < 0) || (idx >= MAX_PKTGEN)) {
973                 printk("ERROR: idx: %i is out of range in proc_write\n", idx);
974                 return -EINVAL;
975         }
976         info = &(pginfos[idx]);
977         result = &(info->result[0]);
978         
979         if (count < 1) {
980                 sprintf(result, "Wrong command format");
981                 return -EINVAL;
982         }
983   
984         max = count - i;
985         tmp = count_trail_chars(&user_buffer[i], max);
986         if (tmp < 0)
987                 return tmp;
988         i += tmp;
989   
990         /* Read variable name */
991
992         len = strn_len(&user_buffer[i], sizeof(name) - 1);
993         if (len < 0)
994                 return len;
995         memset(name, 0, sizeof(name));
996         if (copy_from_user(name, &user_buffer[i], len))
997                 return -EFAULT;
998         i += len;
999   
1000         max = count -i;
1001         len = count_trail_chars(&user_buffer[i], max);
1002         if (len < 0)
1003                 return len;
1004         i += len;
1005
1006         if (debug)
1007                 printk("pg: %s,%lu\n", name, count);
1008
1009         if (!strcmp(name, "stop")) {
1010                 if (info->do_run_run) {
1011                         strcpy(result, "Stopping");
1012                 }
1013                 else {
1014                         strcpy(result, "Already stopped...\n");
1015                 }
1016                 info->do_run_run = 0;
1017                 return count;
1018         }
1019
1020         if (!strcmp(name, "pkt_size")) {
1021                 len = num_arg(&user_buffer[i], 10, &value);
1022                 if (len < 0)
1023                         return len;
1024                 i += len;
1025                 if (value < 14+20+8)
1026                         value = 14+20+8;
1027                 info->pkt_size = value;
1028                 sprintf(result, "OK: pkt_size=%u", info->pkt_size);
1029                 return count;
1030         }
1031         if (!strcmp(name, "frags")) {
1032                 len = num_arg(&user_buffer[i], 10, &value);
1033                 if (len < 0)
1034                         return len;
1035                 i += len;
1036                 info->nfrags = value;
1037                 sprintf(result, "OK: frags=%u", info->nfrags);
1038                 return count;
1039         }
1040         if (!strcmp(name, "ipg")) {
1041                 len = num_arg(&user_buffer[i], 10, &value);
1042                 if (len < 0)
1043                         return len;
1044                 i += len;
1045                 info->ipg = value;
1046                 sprintf(result, "OK: ipg=%u", info->ipg);
1047                 return count;
1048         }
1049         if (!strcmp(name, "udp_src_min")) {
1050                 len = num_arg(&user_buffer[i], 10, &value);
1051                 if (len < 0)
1052                         return len;
1053                 i += len;
1054                 info->udp_src_min = value;
1055                 sprintf(result, "OK: udp_src_min=%u", info->udp_src_min);
1056                 return count;
1057         }
1058         if (!strcmp(name, "udp_dst_min")) {
1059                 len = num_arg(&user_buffer[i], 10, &value);
1060                 if (len < 0)
1061                         return len;
1062                 i += len;
1063                 info->udp_dst_min = value;
1064                 sprintf(result, "OK: udp_dst_min=%u", info->udp_dst_min);
1065                 return count;
1066         }
1067         if (!strcmp(name, "udp_src_max")) {
1068                 len = num_arg(&user_buffer[i], 10, &value);
1069                 if (len < 0)
1070                         return len;
1071                 i += len;
1072                 info->udp_src_max = value;
1073                 sprintf(result, "OK: udp_src_max=%u", info->udp_src_max);
1074                 return count;
1075         }
1076         if (!strcmp(name, "udp_dst_max")) {
1077                 len = num_arg(&user_buffer[i], 10, &value);
1078                 if (len < 0)
1079                         return len;
1080                 i += len;
1081                 info->udp_dst_max = value;
1082                 sprintf(result, "OK: udp_dst_max=%u", info->udp_dst_max);
1083                 return count;
1084         }
1085         if (!strcmp(name, "clone_skb")) {
1086                 len = num_arg(&user_buffer[i], 10, &value);
1087                 if (len < 0)
1088                         return len;
1089                 i += len;
1090                 info->clone_skb = value;
1091         
1092                 sprintf(result, "OK: clone_skb=%d", info->clone_skb);
1093                 return count;
1094         }
1095         if (!strcmp(name, "count")) {
1096                 len = num_arg(&user_buffer[i], 10, &value);
1097                 if (len < 0)
1098                         return len;
1099                 i += len;
1100                 info->count = value;
1101                 sprintf(result, "OK: count=%llu", (unsigned long long) info->count);
1102                 return count;
1103         }
1104         if (!strcmp(name, "src_mac_count")) {
1105                 len = num_arg(&user_buffer[i], 10, &value);
1106                 if (len < 0)
1107                         return len;
1108                 i += len;
1109                 info->src_mac_count = value;
1110                 sprintf(result, "OK: src_mac_count=%d", info->src_mac_count);
1111                 return count;
1112         }
1113         if (!strcmp(name, "dst_mac_count")) {
1114                 len = num_arg(&user_buffer[i], 10, &value);
1115                 if (len < 0)
1116                         return len;
1117                 i += len;
1118                 info->dst_mac_count = value;
1119                 sprintf(result, "OK: dst_mac_count=%d", info->dst_mac_count);
1120                 return count;
1121         }
1122         if (!strcmp(name, "odev")) {
1123                 len = strn_len(&user_buffer[i], sizeof(info->outdev) - 1);
1124                 if (len < 0)
1125                         return len;
1126                 memset(info->outdev, 0, sizeof(info->outdev));
1127                 if (copy_from_user(info->outdev, &user_buffer[i], len))
1128                         return -EFAULT;
1129                 i += len;
1130                 sprintf(result, "OK: odev=%s", info->outdev);
1131                 return count;
1132         }
1133         if (!strcmp(name, "flag")) {
1134                 char f[32];
1135                 len = strn_len(&user_buffer[i], sizeof(f) - 1);
1136                 if (len < 0)
1137                         return len;
1138                 memset(f, 0, 32);
1139                 if (copy_from_user(f, &user_buffer[i], len))
1140                         return -EFAULT;
1141                 i += len;
1142                 if (strcmp(f, "IPSRC_RND") == 0) {
1143                         info->flags |= F_IPSRC_RND;
1144                 }
1145                 else if (strcmp(f, "!IPSRC_RND") == 0) {
1146                         info->flags &= ~F_IPSRC_RND;
1147                 }
1148                 else if (strcmp(f, "IPDST_RND") == 0) {
1149                         info->flags |= F_IPDST_RND;
1150                 }
1151                 else if (strcmp(f, "!IPDST_RND") == 0) {
1152                         info->flags &= ~F_IPDST_RND;
1153                 }
1154                 else if (strcmp(f, "UDPSRC_RND") == 0) {
1155                         info->flags |= F_UDPSRC_RND;
1156                 }
1157                 else if (strcmp(f, "!UDPSRC_RND") == 0) {
1158                         info->flags &= ~F_UDPSRC_RND;
1159                 }
1160                 else if (strcmp(f, "UDPDST_RND") == 0) {
1161                         info->flags |= F_UDPDST_RND;
1162                 }
1163                 else if (strcmp(f, "!UDPDST_RND") == 0) {
1164                         info->flags &= ~F_UDPDST_RND;
1165                 }
1166                 else if (strcmp(f, "MACSRC_RND") == 0) {
1167                         info->flags |= F_MACSRC_RND;
1168                 }
1169                 else if (strcmp(f, "!MACSRC_RND") == 0) {
1170                         info->flags &= ~F_MACSRC_RND;
1171                 }
1172                 else if (strcmp(f, "MACDST_RND") == 0) {
1173                         info->flags |= F_MACDST_RND;
1174                 }
1175                 else if (strcmp(f, "!MACDST_RND") == 0) {
1176                         info->flags &= ~F_MACDST_RND;
1177                 }
1178                 else {
1179                         sprintf(result, "Flag -:%s:- unknown\nAvailable flags, (prepend ! to un-set flag):\n%s",
1180                                 f,
1181                                 "IPSRC_RND, IPDST_RND, UDPSRC_RND, UDPDST_RND, MACSRC_RND, MACDST_RND\n");
1182                         return count;
1183                 }
1184                 sprintf(result, "OK: flags=0x%x", info->flags);
1185                 return count;
1186         }
1187         if (!strcmp(name, "dst_min") || !strcmp(name, "dst")) {
1188                 len = strn_len(&user_buffer[i], sizeof(info->dst_min) - 1);
1189                 if (len < 0)
1190                         return len;
1191                 memset(info->dst_min, 0, sizeof(info->dst_min));
1192                 if (copy_from_user(info->dst_min, &user_buffer[i], len))
1193                         return -EFAULT;
1194                 if(debug)
1195                         printk("pg: dst_min set to: %s\n", info->dst_min);
1196                 i += len;
1197                 sprintf(result, "OK: dst_min=%s", info->dst_min);
1198                 return count;
1199         }
1200         if (!strcmp(name, "dst_max")) {
1201                 len = strn_len(&user_buffer[i], sizeof(info->dst_max) - 1);
1202                 if (len < 0)
1203                         return len;
1204                 memset(info->dst_max, 0, sizeof(info->dst_max));
1205                 if (copy_from_user(info->dst_max, &user_buffer[i], len))
1206                         return -EFAULT;
1207                 if(debug)
1208                         printk("pg: dst_max set to: %s\n", info->dst_max);
1209                 i += len;
1210                 sprintf(result, "OK: dst_max=%s", info->dst_max);
1211                 return count;
1212         }
1213         if (!strcmp(name, "src_min")) {
1214                 len = strn_len(&user_buffer[i], sizeof(info->src_min) - 1);
1215                 if (len < 0)
1216                         return len;
1217                 memset(info->src_min, 0, sizeof(info->src_min));
1218                 if (copy_from_user(info->src_min, &user_buffer[i], len))
1219                         return -EFAULT;
1220                 if(debug)
1221                         printk("pg: src_min set to: %s\n", info->src_min);
1222                 i += len;
1223                 sprintf(result, "OK: src_min=%s", info->src_min);
1224                 return count;
1225         }
1226         if (!strcmp(name, "src_max")) {
1227                 len = strn_len(&user_buffer[i], sizeof(info->src_max) - 1);
1228                 if (len < 0)
1229                         return len;
1230                 memset(info->src_max, 0, sizeof(info->src_max));
1231                 if (copy_from_user(info->src_max, &user_buffer[i], len))
1232                         return -EFAULT;
1233                 if(debug)
1234                         printk("pg: src_max set to: %s\n", info->src_max);
1235                 i += len;
1236                 sprintf(result, "OK: src_max=%s", info->src_max);
1237                 return count;
1238         }
1239         if (!strcmp(name, "dstmac")) {
1240                 char *v = valstr;
1241                 unsigned char *m = info->dst_mac;
1242
1243                 len = strn_len(&user_buffer[i], sizeof(valstr) - 1);
1244                 if (len < 0)
1245                         return len;
1246                 memset(valstr, 0, sizeof(valstr));
1247                 if (copy_from_user(valstr, &user_buffer[i], len))
1248                         return -EFAULT;
1249                 i += len;
1250
1251                 for(*m = 0;*v && m < info->dst_mac + 6; v++) {
1252                         if (*v >= '0' && *v <= '9') {
1253                                 *m *= 16;
1254                                 *m += *v - '0';
1255                         }
1256                         if (*v >= 'A' && *v <= 'F') {
1257                                 *m *= 16;
1258                                 *m += *v - 'A' + 10;
1259                         }
1260                         if (*v >= 'a' && *v <= 'f') {
1261                                 *m *= 16;
1262                                 *m += *v - 'a' + 10;
1263                         }
1264                         if (*v == ':') {
1265                                 m++;
1266                                 *m = 0;
1267                         }
1268                 }         
1269                 sprintf(result, "OK: dstmac");
1270                 return count;
1271         }
1272         if (!strcmp(name, "srcmac")) {
1273                 char *v = valstr;
1274                 unsigned char *m = info->src_mac;
1275
1276                 len = strn_len(&user_buffer[i], sizeof(valstr) - 1);
1277                 if (len < 0)
1278                         return len;
1279                 memset(valstr, 0, sizeof(valstr));
1280                 if (copy_from_user(valstr, &user_buffer[i], len))
1281                         return -EFAULT;
1282                 i += len;
1283
1284                 for(*m = 0;*v && m < info->src_mac + 6; v++) {
1285                         if (*v >= '0' && *v <= '9') {
1286                                 *m *= 16;
1287                                 *m += *v - '0';
1288                         }
1289                         if (*v >= 'A' && *v <= 'F') {
1290                                 *m *= 16;
1291                                 *m += *v - 'A' + 10;
1292                         }
1293                         if (*v >= 'a' && *v <= 'f') {
1294                                 *m *= 16;
1295                                 *m += *v - 'a' + 10;
1296                         }
1297                         if (*v == ':') {
1298                                 m++;
1299                                 *m = 0;
1300                         }
1301                 }         
1302                 sprintf(result, "OK: srcmac");
1303                 return count;
1304         }
1305
1306         if (!strcmp(name, "inject") || !strcmp(name, "start")) {
1307                 if (info->busy) {
1308                         strcpy(info->result, "Already running...\n");
1309                 }
1310                 else {
1311                         info->busy = 1;
1312                         strcpy(info->result, "Starting");
1313                         inject(info);
1314                         info->busy = 0;
1315                 }
1316                 return count;
1317         }
1318
1319         sprintf(info->result, "No such parameter \"%s\"", name);
1320         return -EINVAL;
1321 }
1322
1323
1324 static int create_proc_dir(void)
1325 {
1326         int     len;
1327         /*  does proc_dir already exists */
1328         len = strlen(PG_PROC_DIR);
1329
1330         for (proc_dir = proc_net->subdir; proc_dir;
1331              proc_dir=proc_dir->next) {
1332                 if ((proc_dir->namelen == len) &&
1333                     (! memcmp(proc_dir->name, PG_PROC_DIR, len)))
1334                         break;
1335         }
1336         if (!proc_dir)
1337                 proc_dir = create_proc_entry(PG_PROC_DIR, S_IFDIR, proc_net);
1338         if (!proc_dir) return -ENODEV;
1339         return 1;
1340 }
1341
1342 static int remove_proc_dir(void)
1343 {
1344         remove_proc_entry(PG_PROC_DIR, proc_net);
1345         return 1;
1346 }
1347
1348 static int __init init(void)
1349 {
1350         int i;
1351         printk(version);
1352         cycles_calibrate();
1353         if (cpu_speed == 0) {
1354                 printk("pktgen: Error: your machine does not have working cycle counter.\n");
1355                 return -EINVAL;
1356         }
1357
1358         create_proc_dir();
1359
1360         for (i = 0; i<MAX_PKTGEN; i++) {
1361                 memset(&(pginfos[i]), 0, sizeof(pginfos[i]));
1362                 pginfos[i].pkt_size = ETH_ZLEN;
1363                 pginfos[i].nfrags = 0;
1364                 pginfos[i].clone_skb = clone_skb_d;
1365                 pginfos[i].ipg = ipg_d;
1366                 pginfos[i].count = count_d;
1367                 pginfos[i].sofar = 0;
1368                 pginfos[i].hh[12] = 0x08; /* fill in protocol.  Rest is filled in later. */
1369                 pginfos[i].hh[13] = 0x00;
1370                 pginfos[i].udp_src_min = 9; /* sink NULL */
1371                 pginfos[i].udp_src_max = 9;
1372                 pginfos[i].udp_dst_min = 9;
1373                 pginfos[i].udp_dst_max = 9;
1374                 
1375                 sprintf(pginfos[i].fname, "net/%s/pg%i", PG_PROC_DIR, i);
1376                 pginfos[i].proc_ent = create_proc_entry(pginfos[i].fname, 0600, NULL);
1377                 if (!pginfos[i].proc_ent) {
1378                         printk("pktgen: Error: cannot create net/%s/pg procfs entry.\n", PG_PROC_DIR);
1379                         goto cleanup_mem;
1380                 }
1381                 pginfos[i].proc_ent->read_proc = proc_read;
1382                 pginfos[i].proc_ent->write_proc = proc_write;
1383                 pginfos[i].proc_ent->data = (void*)(long)(i);
1384                 pginfos[i].proc_ent->owner = THIS_MODULE;
1385
1386                 sprintf(pginfos[i].busy_fname, "net/%s/pg_busy%i",  PG_PROC_DIR, i);
1387                 pginfos[i].busy_proc_ent = create_proc_entry(pginfos[i].busy_fname, 0, NULL);
1388                 if (!pginfos[i].busy_proc_ent) {
1389                         printk("pktgen: Error: cannot create net/%s/pg_busy procfs entry.\n", PG_PROC_DIR);
1390                         goto cleanup_mem;
1391                 }
1392                 pginfos[i].busy_proc_ent->read_proc = proc_busy_read;
1393                 pginfos[i].busy_proc_ent->data = (void*)(long)(i);
1394         }
1395         return 0;
1396         
1397 cleanup_mem:
1398         for (i = 0; i<MAX_PKTGEN; i++) {
1399                 if (strlen(pginfos[i].fname)) {
1400                         remove_proc_entry(pginfos[i].fname, NULL);
1401                 }
1402                 if (strlen(pginfos[i].busy_fname)) {
1403                         remove_proc_entry(pginfos[i].busy_fname, NULL);
1404                 }
1405         }
1406         return -ENOMEM;
1407 }
1408
1409
1410 static void __exit cleanup(void)
1411 {
1412         int i;
1413         for (i = 0; i<MAX_PKTGEN; i++) {
1414                 if (strlen(pginfos[i].fname)) {
1415                         remove_proc_entry(pginfos[i].fname, NULL);
1416                 }
1417                 if (strlen(pginfos[i].busy_fname)) {
1418                         remove_proc_entry(pginfos[i].busy_fname, NULL);
1419                 }
1420         }
1421         remove_proc_dir();
1422 }
1423
1424 module_init(init);
1425 module_exit(cleanup);
1426
1427 MODULE_AUTHOR("Robert Olsson <robert.olsson@its.uu.se");
1428 MODULE_DESCRIPTION("Packet Generator tool");
1429 MODULE_LICENSE("GPL");
1430 module_param(count_d, int, 0);
1431 module_param(ipg_d, int, 0);
1432 module_param(cpu_speed, int, 0);
1433 module_param(clone_skb_d, int, 0);