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