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