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