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