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