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