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