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
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
47 * Also moved to /proc/net/pktgen/
50 * Fix refcount off by one if first packet fails, potential null deref,
53 * Fixed unaligned access on IA-64 Grant Grundler <grundler@parisc-linux.org>
55 * New xmit() return, do_div and misc clean up by Stephen Hemminger
56 * <shemminger@osdl.org> 040923
58 * See Documentation/networking/pktgen.txt for how to use this.
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/delay.h>
73 #include <linux/init.h>
74 #include <linux/inet.h>
75 #include <linux/rcupdate.h>
76 #include <linux/bitops.h>
77 #include <asm/byteorder.h>
80 #include <asm/uaccess.h>
84 #include <linux/udp.h>
85 #include <linux/skbuff.h>
86 #include <linux/netdevice.h>
87 #include <linux/inetdevice.h>
88 #include <linux/rtnetlink.h>
89 #include <linux/proc_fs.h>
90 #include <linux/if_arp.h>
91 #include <net/checksum.h>
92 #include <asm/timex.h>
94 #define cycles() ((u32)get_cycles())
97 #define VERSION "pktgen version 1.32"
98 static char version[] __initdata =
99 "pktgen.c: v1.4: Packet Generator for packet performance testing.\n";
101 /* Used to help with determining the pkts on receive */
103 #define PKTGEN_MAGIC 0xbe9be955
106 /* Keep information per interface */
110 /* If min != max, then we will either do a linear iteration, or
111 * we will do a random selection from within the range.
115 #define F_IPSRC_RND (1<<0) /* IP-Src Random */
116 #define F_IPDST_RND (1<<1) /* IP-Dst Random */
117 #define F_UDPSRC_RND (1<<2) /* UDP-Src Random */
118 #define F_UDPDST_RND (1<<3) /* UDP-Dst Random */
119 #define F_MACSRC_RND (1<<4) /* MAC-Src Random */
120 #define F_MACDST_RND (1<<5) /* MAC-Dst Random */
121 #define F_SET_SRCMAC (1<<6) /* Specify-Src-Mac
122 (default is to use Interface's MAC Addr) */
123 #define F_SET_SRCIP (1<<7) /* Specify-Src-IP
124 (default is to use Interface's IP Addr) */
127 int pkt_size; /* = ETH_ZLEN; */
129 __u32 ipg; /* Default Interpacket gap in nsec */
130 __u64 count; /* Default No packets to send */
131 __u64 sofar; /* How many pkts we've sent so far */
132 __u64 errors; /* Errors when trying to transmit, pkts will be re-sent */
133 struct timeval started_at;
134 struct timeval stopped_at;
138 int clone_skb; /* Use multiple SKBs during packet gen. If this number
139 * is greater than 1, then that many coppies of the same
140 * packet will be sent before a new packet is allocated.
141 * For instance, if you want to send 1024 identical packets
142 * before creating a new packet, set clone_skb to 1024.
145 int do_run_run; /* if this changes to false, the test will stop */
153 /* If we're doing ranges, random or incremental, then this
154 * defines the min/max for those ranges.
156 __u32 saddr_min; /* inclusive, source IP address */
157 __u32 saddr_max; /* exclusive, source IP address */
158 __u32 daddr_min; /* inclusive, dest IP address */
159 __u32 daddr_max; /* exclusive, dest IP address */
161 __u16 udp_src_min; /* inclusive, source UDP port */
162 __u16 udp_src_max; /* exclusive, source UDP port */
163 __u16 udp_dst_min; /* inclusive, dest UDP port */
164 __u16 udp_dst_max; /* exclusive, dest UDP port */
166 __u32 src_mac_count; /* How many MACs to iterate through */
167 __u32 dst_mac_count; /* How many MACs to iterate through */
169 unsigned char dst_mac[6];
170 unsigned char src_mac[6];
172 __u32 cur_dst_mac_offset;
173 __u32 cur_src_mac_offset;
181 0x00, 0x80, 0xC8, 0x79, 0xB3, 0xCB,
183 We fill in SRC address later
184 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
188 __u16 pad; /* pad out the hh struct to an even 16 bytes */
191 /* proc file names */
195 struct proc_dir_entry *proc_ent;
196 struct proc_dir_entry *busy_proc_ent;
206 static int cpu_speed;
209 /* Module parameters, defaults. */
210 static int count_d = 100000;
212 static int clone_skb_d;
216 static struct pktgen_info pginfos[MAX_PKTGEN];
219 /** Convert to miliseconds */
220 static inline __u64 tv_to_ms(const struct timeval* tv) {
221 __u64 ms = tv->tv_usec / 1000;
222 ms += (__u64)tv->tv_sec * (__u64)1000;
226 static inline __u64 getCurMs(void) {
228 do_gettimeofday(&tv);
229 return tv_to_ms(&tv);
232 #define PG_PROC_DIR "pktgen"
233 static struct proc_dir_entry *proc_dir;
235 static struct net_device *setup_inject(struct pktgen_info* info)
237 struct net_device *odev;
239 odev = dev_get_by_name(info->outdev);
241 sprintf(info->result, "No such netdevice: \"%s\"", info->outdev);
245 if (odev->type != ARPHRD_ETHER) {
246 sprintf(info->result, "Not ethernet device: \"%s\"", info->outdev);
250 if (!netif_running(odev)) {
251 sprintf(info->result, "Device is down: \"%s\"", info->outdev);
255 /* Default to the interface's mac if not explicitly set. */
256 if (!(info->flags & F_SET_SRCMAC)) {
257 memcpy(&(info->hh[6]), odev->dev_addr, 6);
260 memcpy(&(info->hh[6]), info->src_mac, 6);
263 /* Set up Dest MAC */
264 memcpy(&(info->hh[0]), info->dst_mac, 6);
268 if (strlen(info->src_min) == 0) {
269 struct in_device *in_dev;
272 in_dev = __in_dev_get(odev);
274 if (in_dev->ifa_list) {
275 info->saddr_min = in_dev->ifa_list->ifa_address;
276 info->saddr_max = info->saddr_min;
282 info->saddr_min = in_aton(info->src_min);
283 info->saddr_max = in_aton(info->src_max);
286 info->daddr_min = in_aton(info->dst_min);
287 info->daddr_max = in_aton(info->dst_max);
289 /* Initialize current values. */
290 info->cur_dst_mac_offset = 0;
291 info->cur_src_mac_offset = 0;
292 info->cur_saddr = info->saddr_min;
293 info->cur_daddr = info->daddr_min;
294 info->cur_udp_dst = info->udp_dst_min;
295 info->cur_udp_src = info->udp_src_min;
305 static void nanospin(int ipg, struct pktgen_info* info)
307 u32 idle_start, idle;
309 idle_start = cycles();
313 idle = cycles() - idle_start;
314 if (idle * 1000 >= ipg * cpu_speed)
317 info->idle_acc += idle;
320 static int calc_mhz(void)
322 struct timeval start, stop;
323 u32 start_s, elapsed;
325 do_gettimeofday(&start);
329 elapsed = cycles() - start_s;
332 } while (elapsed < 1000 * 50000);
333 do_gettimeofday(&stop);
334 return elapsed/(stop.tv_usec-start.tv_usec+1000000*(stop.tv_sec-start.tv_sec));
337 static void cycles_calibrate(void)
341 for (i = 0; i < 3; i++) {
342 int res = calc_mhz();
349 /* Increment/randomize headers according to flags and current values
350 * for IP src/dest, UDP src/dst port, MAC-Addr src/dst
352 static void mod_cur_headers(struct pktgen_info* info) {
356 /* Deal with source MAC */
357 if (info->src_mac_count > 1) {
360 if (info->flags & F_MACSRC_RND) {
361 mc = net_random() % (info->src_mac_count);
364 mc = info->cur_src_mac_offset++;
365 if (info->cur_src_mac_offset > info->src_mac_count) {
366 info->cur_src_mac_offset = 0;
370 tmp = info->src_mac[5] + (mc & 0xFF);
372 tmp = (info->src_mac[4] + ((mc >> 8) & 0xFF) + (tmp >> 8));
374 tmp = (info->src_mac[3] + ((mc >> 16) & 0xFF) + (tmp >> 8));
376 tmp = (info->src_mac[2] + ((mc >> 24) & 0xFF) + (tmp >> 8));
378 tmp = (info->src_mac[1] + (tmp >> 8));
382 /* Deal with Destination MAC */
383 if (info->dst_mac_count > 1) {
386 if (info->flags & F_MACDST_RND) {
387 mc = net_random() % (info->dst_mac_count);
390 mc = info->cur_dst_mac_offset++;
391 if (info->cur_dst_mac_offset > info->dst_mac_count) {
392 info->cur_dst_mac_offset = 0;
396 tmp = info->dst_mac[5] + (mc & 0xFF);
398 tmp = (info->dst_mac[4] + ((mc >> 8) & 0xFF) + (tmp >> 8));
400 tmp = (info->dst_mac[3] + ((mc >> 16) & 0xFF) + (tmp >> 8));
402 tmp = (info->dst_mac[2] + ((mc >> 24) & 0xFF) + (tmp >> 8));
404 tmp = (info->dst_mac[1] + (tmp >> 8));
408 if (info->udp_src_min < info->udp_src_max) {
409 if (info->flags & F_UDPSRC_RND) {
410 info->cur_udp_src = ((net_random() % (info->udp_src_max - info->udp_src_min))
411 + info->udp_src_min);
415 if (info->cur_udp_src >= info->udp_src_max) {
416 info->cur_udp_src = info->udp_src_min;
421 if (info->udp_dst_min < info->udp_dst_max) {
422 if (info->flags & F_UDPDST_RND) {
423 info->cur_udp_dst = ((net_random() % (info->udp_dst_max - info->udp_dst_min))
424 + info->udp_dst_min);
428 if (info->cur_udp_dst >= info->udp_dst_max) {
429 info->cur_udp_dst = info->udp_dst_min;
434 if ((imn = ntohl(info->saddr_min)) < (imx = ntohl(info->saddr_max))) {
436 if (info->flags & F_IPSRC_RND) {
437 t = ((net_random() % (imx - imn)) + imn);
440 t = ntohl(info->cur_saddr);
446 info->cur_saddr = htonl(t);
449 if ((imn = ntohl(info->daddr_min)) < (imx = ntohl(info->daddr_max))) {
451 if (info->flags & F_IPDST_RND) {
452 t = ((net_random() % (imx - imn)) + imn);
455 t = ntohl(info->cur_daddr);
461 info->cur_daddr = htonl(t);
463 }/* mod_cur_headers */
466 static struct sk_buff *fill_packet(struct net_device *odev, struct pktgen_info* info)
468 struct sk_buff *skb = NULL;
473 struct pktgen_hdr *pgh = NULL;
475 skb = alloc_skb(info->pkt_size + 64 + 16, GFP_ATOMIC);
477 sprintf(info->result, "No memory");
481 skb_reserve(skb, 16);
483 /* Reserve for ethernet and IP header */
484 eth = (__u8 *) skb_push(skb, 14);
485 iph = (struct iphdr *)skb_put(skb, sizeof(struct iphdr));
486 udph = (struct udphdr *)skb_put(skb, sizeof(struct udphdr));
488 /* Update any of the values, used when we're incrementing various
491 mod_cur_headers(info);
493 memcpy(eth, info->hh, 14);
495 datalen = info->pkt_size - 14 - 20 - 8; /* Eth + IPh + UDPh */
496 if (datalen < sizeof(struct pktgen_hdr)) {
497 datalen = sizeof(struct pktgen_hdr);
500 udph->source = htons(info->cur_udp_src);
501 udph->dest = htons(info->cur_udp_dst);
502 udph->len = htons(datalen + 8); /* DATA + udphdr */
503 udph->check = 0; /* No checksum */
509 iph->protocol = IPPROTO_UDP; /* UDP */
510 iph->saddr = info->cur_saddr;
511 iph->daddr = info->cur_daddr;
513 iplen = 20 + 8 + datalen;
514 iph->tot_len = htons(iplen);
516 iph->check = ip_fast_csum((void *) iph, iph->ihl);
517 skb->protocol = __constant_htons(ETH_P_IP);
518 skb->mac.raw = ((u8 *)iph) - 14;
520 skb->pkt_type = PACKET_HOST;
522 if (info->nfrags <= 0) {
523 pgh = (struct pktgen_hdr *)skb_put(skb, datalen);
525 int frags = info->nfrags;
528 /* TODO: Verify this is OK...it sure is ugly. --Ben */
529 pgh = (struct pktgen_hdr*)(((char*)(udph)) + 8);
531 if (frags > MAX_SKB_FRAGS)
532 frags = MAX_SKB_FRAGS;
533 if (datalen > frags*PAGE_SIZE) {
534 skb_put(skb, datalen-frags*PAGE_SIZE);
535 datalen = frags*PAGE_SIZE;
539 while (datalen > 0) {
540 struct page *page = alloc_pages(GFP_KERNEL, 0);
541 skb_shinfo(skb)->frags[i].page = page;
542 skb_shinfo(skb)->frags[i].page_offset = 0;
543 skb_shinfo(skb)->frags[i].size =
544 (datalen < PAGE_SIZE ? datalen : PAGE_SIZE);
545 datalen -= skb_shinfo(skb)->frags[i].size;
546 skb->len += skb_shinfo(skb)->frags[i].size;
547 skb->data_len += skb_shinfo(skb)->frags[i].size;
549 skb_shinfo(skb)->nr_frags = i;
558 rem = skb_shinfo(skb)->frags[i - 1].size / 2;
562 skb_shinfo(skb)->frags[i - 1].size -= rem;
564 skb_shinfo(skb)->frags[i] = skb_shinfo(skb)->frags[i - 1];
565 get_page(skb_shinfo(skb)->frags[i].page);
566 skb_shinfo(skb)->frags[i].page = skb_shinfo(skb)->frags[i - 1].page;
567 skb_shinfo(skb)->frags[i].page_offset += skb_shinfo(skb)->frags[i - 1].size;
568 skb_shinfo(skb)->frags[i].size = rem;
570 skb_shinfo(skb)->nr_frags = i;
574 /* Stamp the time, and sequence number, convert them to network byte order */
576 struct timeval timestamp;
578 pgh->pgh_magic = htonl(PKTGEN_MAGIC);
579 pgh->seq_num = htonl(info->seq_num);
581 do_gettimeofday(×tamp);
582 pgh->tv_sec = htonl(timestamp.tv_sec);
583 pgh->tv_usec = htonl(timestamp.tv_usec);
589 static void show_results(struct pktgen_info* info, int nr_frags)
591 __u64 total, bps, mbps, pps;
593 int size = info->pkt_size + 4; /* incl 32bit ethernet CRC */
594 char *p = info->result;
596 total = (info->stopped_at.tv_sec - info->started_at.tv_sec) * 1000000ull
597 + info->stopped_at.tv_usec - info->started_at.tv_usec;
599 BUG_ON(cpu_speed == 0);
601 idle = info->idle_acc;
602 do_div(idle, cpu_speed);
604 p += sprintf(p, "OK: %llu(c%llu+d%lu) usec, %llu (%dbyte,%dfrags)\n",
605 (unsigned long long) total,
606 (unsigned long long) (total - idle), idle,
607 (unsigned long long) info->sofar,
610 pps = info->sofar * USEC_PER_SEC;
612 while ((total >> 32) != 0) {
619 bps = pps * 8 * size;
622 do_div(mbps, 1000000);
623 p += sprintf(p, " %llupps %lluMb/sec (%llubps) errors: %llu",
624 (unsigned long long) pps,
625 (unsigned long long) mbps,
626 (unsigned long long) bps,
627 (unsigned long long) info->errors);
630 static void inject(struct pktgen_info* info)
632 struct net_device *odev;
633 struct sk_buff *skb = NULL;
636 int last_ok = 1; /* Was last skb sent?
637 * Or a failed transmit of some sort? This will keep
638 * sequence numbers in order, for example.
643 odev = setup_inject(info);
647 info->do_run_run = 1; /* Cranke yeself! */
651 lcount = info->count;
654 /* Build our initial pkt and place it as a re-try pkt. */
655 skb = fill_packet(odev, info);
656 if (skb == NULL) goto out_reldev;
658 do_gettimeofday(&(info->started_at));
660 while(info->do_run_run) {
662 /* Set a time-stamp, so build a new pkt each time */
665 if (++fp_tmp >= info->clone_skb ) {
667 skb = fill_packet(odev, info);
672 fp_tmp = 0; /* reset counter */
676 if (!(odev->features & NETIF_F_LLTX))
677 spin_lock_bh(&odev->xmit_lock);
678 if (!netif_queue_stopped(odev)) {
680 atomic_inc(&skb->users);
683 ret = odev->hard_start_xmit(skb, odev);
684 if (likely(ret == NETDEV_TX_OK)) {
688 } else if (ret == NETDEV_TX_LOCKED
689 && (odev->features & NETIF_F_LLTX)) {
693 atomic_dec(&skb->users);
694 if (debug && net_ratelimit()) {
695 printk(KERN_INFO "Hard xmit error\n");
702 /* Re-try it next time */
706 if (!(odev->features & NETIF_F_LLTX))
707 spin_unlock_bh(&odev->xmit_lock);
710 /* Try not to busy-spin if we have larger sleep times.
711 * TODO: Investigate better ways to do this.
713 if (info->ipg < 10000) { /* 10 usecs or less */
714 nanospin(info->ipg, info);
716 else if (info->ipg < 10000000) { /* 10ms or less */
717 udelay(info->ipg / 1000);
720 mdelay(info->ipg / 1000000);
724 if (signal_pending(current)) {
728 /* If lcount is zero, then run forever */
729 if ((lcount != 0) && (--lcount == 0)) {
730 if (atomic_read(&skb->users) != 1) {
731 u32 idle_start, idle;
733 idle_start = cycles();
734 while (atomic_read(&skb->users) != 1) {
735 if (signal_pending(current)) {
740 idle = cycles() - idle_start;
741 info->idle_acc += idle;
746 if (netif_queue_stopped(odev) || need_resched()) {
747 u32 idle_start, idle;
749 idle_start = cycles();
751 if (signal_pending(current)) {
752 info->do_run_run = 0;
755 if (!netif_running(odev)) {
756 info->do_run_run = 0;
763 } while (netif_queue_stopped(odev));
764 idle = cycles() - idle_start;
765 info->idle_acc += idle;
767 }/* while we should be running */
769 do_gettimeofday(&(info->stopped_at));
771 show_results(info, skb_shinfo(skb)->nr_frags);
785 /* proc/net/pktgen/pg */
787 static int proc_busy_read(char *buf , char **start, off_t offset,
788 int len, int *eof, void *data)
791 int idx = (int)(long)(data);
792 struct pktgen_info* info = NULL;
794 if ((idx < 0) || (idx >= MAX_PKTGEN)) {
795 printk("ERROR: idx: %i is out of range in proc_write\n", idx);
798 info = &(pginfos[idx]);
801 p += sprintf(p, "%d\n", info->busy);
807 static int proc_read(char *buf , char **start, off_t offset,
808 int len, int *eof, void *data)
812 int idx = (int)(long)(data);
813 struct pktgen_info* info = NULL;
816 __u64 now = getCurMs();
818 if ((idx < 0) || (idx >= MAX_PKTGEN)) {
819 printk("ERROR: idx: %i is out of range in proc_write\n", idx);
822 info = &(pginfos[idx]);
825 p += sprintf(p, "%s\n", VERSION); /* Help with parsing compatibility */
826 p += sprintf(p, "Params: count %llu pkt_size: %u frags: %d ipg: %u clone_skb: %d odev \"%s\"\n",
827 (unsigned long long) info->count,
828 info->pkt_size, info->nfrags, info->ipg,
829 info->clone_skb, info->outdev);
830 p += sprintf(p, " dst_min: %s dst_max: %s src_min: %s src_max: %s\n",
831 info->dst_min, info->dst_max, info->src_min, info->src_max);
832 p += sprintf(p, " src_mac: ");
833 for (i = 0; i < 6; i++) {
834 p += sprintf(p, "%02X%s", info->src_mac[i], i == 5 ? " " : ":");
836 p += sprintf(p, "dst_mac: ");
837 for (i = 0; i < 6; i++) {
838 p += sprintf(p, "%02X%s", info->dst_mac[i], i == 5 ? "\n" : ":");
840 p += sprintf(p, " udp_src_min: %d udp_src_max: %d udp_dst_min: %d udp_dst_max: %d\n",
841 info->udp_src_min, info->udp_src_max, info->udp_dst_min,
843 p += sprintf(p, " src_mac_count: %d dst_mac_count: %d\n Flags: ",
844 info->src_mac_count, info->dst_mac_count);
845 if (info->flags & F_IPSRC_RND) {
846 p += sprintf(p, "IPSRC_RND ");
848 if (info->flags & F_IPDST_RND) {
849 p += sprintf(p, "IPDST_RND ");
851 if (info->flags & F_UDPSRC_RND) {
852 p += sprintf(p, "UDPSRC_RND ");
854 if (info->flags & F_UDPDST_RND) {
855 p += sprintf(p, "UDPDST_RND ");
857 if (info->flags & F_MACSRC_RND) {
858 p += sprintf(p, "MACSRC_RND ");
860 if (info->flags & F_MACDST_RND) {
861 p += sprintf(p, "MACDST_RND ");
863 p += sprintf(p, "\n");
865 sa = tv_to_ms(&(info->started_at));
866 stopped = tv_to_ms(&(info->stopped_at));
867 if (info->do_run_run) {
868 stopped = now; /* not really stopped, more like last-running-at */
870 p += sprintf(p, "Current:\n pkts-sofar: %llu errors: %llu\n started: %llums stopped: %llums now: %llums idle: %lluns\n",
871 (unsigned long long) info->sofar,
872 (unsigned long long) info->errors,
873 (unsigned long long) sa,
874 (unsigned long long) stopped,
875 (unsigned long long) now,
876 (unsigned long long) info->idle_acc);
877 p += sprintf(p, " seq_num: %d cur_dst_mac_offset: %d cur_src_mac_offset: %d\n",
878 info->seq_num, info->cur_dst_mac_offset, info->cur_src_mac_offset);
879 p += sprintf(p, " cur_saddr: 0x%x cur_daddr: 0x%x cur_udp_dst: %d cur_udp_src: %d\n",
880 info->cur_saddr, info->cur_daddr, info->cur_udp_dst, info->cur_udp_src);
883 p += sprintf(p, "Result: %s\n", info->result);
885 p += sprintf(p, "Result: Idle\n");
891 static int count_trail_chars(const char __user *user_buffer, unsigned int maxlen)
895 for (i = 0; i < maxlen; i++) {
898 if (get_user(c, &user_buffer[i]))
916 static unsigned long num_arg(const char __user *user_buffer, unsigned long maxlen,
923 for(; i < maxlen; i++) {
926 if (get_user(c, &user_buffer[i]))
928 if ((c >= '0') && (c <= '9')) {
937 static int strn_len(const char __user *user_buffer, unsigned int maxlen)
941 for(; i < maxlen; i++) {
944 if (get_user(c, &user_buffer[i]))
961 static int proc_write(struct file *file, const char __user *user_buffer,
962 unsigned long count, void *data)
965 char name[16], valstr[32];
966 unsigned long value = 0;
967 int idx = (int)(long)(data);
968 struct pktgen_info* info = NULL;
972 if ((idx < 0) || (idx >= MAX_PKTGEN)) {
973 printk("ERROR: idx: %i is out of range in proc_write\n", idx);
976 info = &(pginfos[idx]);
977 result = &(info->result[0]);
980 sprintf(result, "Wrong command format");
985 tmp = count_trail_chars(&user_buffer[i], max);
990 /* Read variable name */
992 len = strn_len(&user_buffer[i], sizeof(name) - 1);
995 memset(name, 0, sizeof(name));
996 if (copy_from_user(name, &user_buffer[i], len))
1001 len = count_trail_chars(&user_buffer[i], max);
1007 printk("pg: %s,%lu\n", name, count);
1009 if (!strcmp(name, "stop")) {
1010 if (info->do_run_run) {
1011 strcpy(result, "Stopping");
1014 strcpy(result, "Already stopped...\n");
1016 info->do_run_run = 0;
1020 if (!strcmp(name, "pkt_size")) {
1021 len = num_arg(&user_buffer[i], 10, &value);
1025 if (value < 14+20+8)
1027 info->pkt_size = value;
1028 sprintf(result, "OK: pkt_size=%u", info->pkt_size);
1031 if (!strcmp(name, "frags")) {
1032 len = num_arg(&user_buffer[i], 10, &value);
1036 info->nfrags = value;
1037 sprintf(result, "OK: frags=%u", info->nfrags);
1040 if (!strcmp(name, "ipg")) {
1041 len = num_arg(&user_buffer[i], 10, &value);
1046 sprintf(result, "OK: ipg=%u", info->ipg);
1049 if (!strcmp(name, "udp_src_min")) {
1050 len = num_arg(&user_buffer[i], 10, &value);
1054 info->udp_src_min = value;
1055 sprintf(result, "OK: udp_src_min=%u", info->udp_src_min);
1058 if (!strcmp(name, "udp_dst_min")) {
1059 len = num_arg(&user_buffer[i], 10, &value);
1063 info->udp_dst_min = value;
1064 sprintf(result, "OK: udp_dst_min=%u", info->udp_dst_min);
1067 if (!strcmp(name, "udp_src_max")) {
1068 len = num_arg(&user_buffer[i], 10, &value);
1072 info->udp_src_max = value;
1073 sprintf(result, "OK: udp_src_max=%u", info->udp_src_max);
1076 if (!strcmp(name, "udp_dst_max")) {
1077 len = num_arg(&user_buffer[i], 10, &value);
1081 info->udp_dst_max = value;
1082 sprintf(result, "OK: udp_dst_max=%u", info->udp_dst_max);
1085 if (!strcmp(name, "clone_skb")) {
1086 len = num_arg(&user_buffer[i], 10, &value);
1090 info->clone_skb = value;
1092 sprintf(result, "OK: clone_skb=%d", info->clone_skb);
1095 if (!strcmp(name, "count")) {
1096 len = num_arg(&user_buffer[i], 10, &value);
1100 info->count = value;
1101 sprintf(result, "OK: count=%llu", (unsigned long long) info->count);
1104 if (!strcmp(name, "src_mac_count")) {
1105 len = num_arg(&user_buffer[i], 10, &value);
1109 info->src_mac_count = value;
1110 sprintf(result, "OK: src_mac_count=%d", info->src_mac_count);
1113 if (!strcmp(name, "dst_mac_count")) {
1114 len = num_arg(&user_buffer[i], 10, &value);
1118 info->dst_mac_count = value;
1119 sprintf(result, "OK: dst_mac_count=%d", info->dst_mac_count);
1122 if (!strcmp(name, "odev")) {
1123 len = strn_len(&user_buffer[i], sizeof(info->outdev) - 1);
1126 memset(info->outdev, 0, sizeof(info->outdev));
1127 if (copy_from_user(info->outdev, &user_buffer[i], len))
1130 sprintf(result, "OK: odev=%s", info->outdev);
1133 if (!strcmp(name, "flag")) {
1135 len = strn_len(&user_buffer[i], sizeof(f) - 1);
1139 if (copy_from_user(f, &user_buffer[i], len))
1142 if (strcmp(f, "IPSRC_RND") == 0) {
1143 info->flags |= F_IPSRC_RND;
1145 else if (strcmp(f, "!IPSRC_RND") == 0) {
1146 info->flags &= ~F_IPSRC_RND;
1148 else if (strcmp(f, "IPDST_RND") == 0) {
1149 info->flags |= F_IPDST_RND;
1151 else if (strcmp(f, "!IPDST_RND") == 0) {
1152 info->flags &= ~F_IPDST_RND;
1154 else if (strcmp(f, "UDPSRC_RND") == 0) {
1155 info->flags |= F_UDPSRC_RND;
1157 else if (strcmp(f, "!UDPSRC_RND") == 0) {
1158 info->flags &= ~F_UDPSRC_RND;
1160 else if (strcmp(f, "UDPDST_RND") == 0) {
1161 info->flags |= F_UDPDST_RND;
1163 else if (strcmp(f, "!UDPDST_RND") == 0) {
1164 info->flags &= ~F_UDPDST_RND;
1166 else if (strcmp(f, "MACSRC_RND") == 0) {
1167 info->flags |= F_MACSRC_RND;
1169 else if (strcmp(f, "!MACSRC_RND") == 0) {
1170 info->flags &= ~F_MACSRC_RND;
1172 else if (strcmp(f, "MACDST_RND") == 0) {
1173 info->flags |= F_MACDST_RND;
1175 else if (strcmp(f, "!MACDST_RND") == 0) {
1176 info->flags &= ~F_MACDST_RND;
1179 sprintf(result, "Flag -:%s:- unknown\nAvailable flags, (prepend ! to un-set flag):\n%s",
1181 "IPSRC_RND, IPDST_RND, UDPSRC_RND, UDPDST_RND, MACSRC_RND, MACDST_RND\n");
1184 sprintf(result, "OK: flags=0x%x", info->flags);
1187 if (!strcmp(name, "dst_min") || !strcmp(name, "dst")) {
1188 len = strn_len(&user_buffer[i], sizeof(info->dst_min) - 1);
1191 memset(info->dst_min, 0, sizeof(info->dst_min));
1192 if (copy_from_user(info->dst_min, &user_buffer[i], len))
1195 printk("pg: dst_min set to: %s\n", info->dst_min);
1197 sprintf(result, "OK: dst_min=%s", info->dst_min);
1200 if (!strcmp(name, "dst_max")) {
1201 len = strn_len(&user_buffer[i], sizeof(info->dst_max) - 1);
1204 memset(info->dst_max, 0, sizeof(info->dst_max));
1205 if (copy_from_user(info->dst_max, &user_buffer[i], len))
1208 printk("pg: dst_max set to: %s\n", info->dst_max);
1210 sprintf(result, "OK: dst_max=%s", info->dst_max);
1213 if (!strcmp(name, "src_min")) {
1214 len = strn_len(&user_buffer[i], sizeof(info->src_min) - 1);
1217 memset(info->src_min, 0, sizeof(info->src_min));
1218 if (copy_from_user(info->src_min, &user_buffer[i], len))
1221 printk("pg: src_min set to: %s\n", info->src_min);
1223 sprintf(result, "OK: src_min=%s", info->src_min);
1226 if (!strcmp(name, "src_max")) {
1227 len = strn_len(&user_buffer[i], sizeof(info->src_max) - 1);
1230 memset(info->src_max, 0, sizeof(info->src_max));
1231 if (copy_from_user(info->src_max, &user_buffer[i], len))
1234 printk("pg: src_max set to: %s\n", info->src_max);
1236 sprintf(result, "OK: src_max=%s", info->src_max);
1239 if (!strcmp(name, "dstmac")) {
1241 unsigned char *m = info->dst_mac;
1243 len = strn_len(&user_buffer[i], sizeof(valstr) - 1);
1246 memset(valstr, 0, sizeof(valstr));
1247 if (copy_from_user(valstr, &user_buffer[i], len))
1251 for(*m = 0;*v && m < info->dst_mac + 6; v++) {
1252 if (*v >= '0' && *v <= '9') {
1256 if (*v >= 'A' && *v <= 'F') {
1258 *m += *v - 'A' + 10;
1260 if (*v >= 'a' && *v <= 'f') {
1262 *m += *v - 'a' + 10;
1269 sprintf(result, "OK: dstmac");
1272 if (!strcmp(name, "srcmac")) {
1274 unsigned char *m = info->src_mac;
1276 len = strn_len(&user_buffer[i], sizeof(valstr) - 1);
1279 memset(valstr, 0, sizeof(valstr));
1280 if (copy_from_user(valstr, &user_buffer[i], len))
1284 for(*m = 0;*v && m < info->src_mac + 6; v++) {
1285 if (*v >= '0' && *v <= '9') {
1289 if (*v >= 'A' && *v <= 'F') {
1291 *m += *v - 'A' + 10;
1293 if (*v >= 'a' && *v <= 'f') {
1295 *m += *v - 'a' + 10;
1302 sprintf(result, "OK: srcmac");
1306 if (!strcmp(name, "inject") || !strcmp(name, "start")) {
1308 strcpy(info->result, "Already running...\n");
1312 strcpy(info->result, "Starting");
1319 sprintf(info->result, "No such parameter \"%s\"", name);
1324 static int create_proc_dir(void)
1327 /* does proc_dir already exists */
1328 len = strlen(PG_PROC_DIR);
1330 for (proc_dir = proc_net->subdir; proc_dir;
1331 proc_dir=proc_dir->next) {
1332 if ((proc_dir->namelen == len) &&
1333 (! memcmp(proc_dir->name, PG_PROC_DIR, len)))
1337 proc_dir = create_proc_entry(PG_PROC_DIR, S_IFDIR, proc_net);
1338 if (!proc_dir) return -ENODEV;
1342 static int remove_proc_dir(void)
1344 remove_proc_entry(PG_PROC_DIR, proc_net);
1348 static int __init init(void)
1353 if (cpu_speed == 0) {
1354 printk("pktgen: Error: your machine does not have working cycle counter.\n");
1360 for (i = 0; i<MAX_PKTGEN; i++) {
1361 memset(&(pginfos[i]), 0, sizeof(pginfos[i]));
1362 pginfos[i].pkt_size = ETH_ZLEN;
1363 pginfos[i].nfrags = 0;
1364 pginfos[i].clone_skb = clone_skb_d;
1365 pginfos[i].ipg = ipg_d;
1366 pginfos[i].count = count_d;
1367 pginfos[i].sofar = 0;
1368 pginfos[i].hh[12] = 0x08; /* fill in protocol. Rest is filled in later. */
1369 pginfos[i].hh[13] = 0x00;
1370 pginfos[i].udp_src_min = 9; /* sink NULL */
1371 pginfos[i].udp_src_max = 9;
1372 pginfos[i].udp_dst_min = 9;
1373 pginfos[i].udp_dst_max = 9;
1375 sprintf(pginfos[i].fname, "net/%s/pg%i", PG_PROC_DIR, i);
1376 pginfos[i].proc_ent = create_proc_entry(pginfos[i].fname, 0600, NULL);
1377 if (!pginfos[i].proc_ent) {
1378 printk("pktgen: Error: cannot create net/%s/pg procfs entry.\n", PG_PROC_DIR);
1381 pginfos[i].proc_ent->read_proc = proc_read;
1382 pginfos[i].proc_ent->write_proc = proc_write;
1383 pginfos[i].proc_ent->data = (void*)(long)(i);
1384 pginfos[i].proc_ent->owner = THIS_MODULE;
1386 sprintf(pginfos[i].busy_fname, "net/%s/pg_busy%i", PG_PROC_DIR, i);
1387 pginfos[i].busy_proc_ent = create_proc_entry(pginfos[i].busy_fname, 0, NULL);
1388 if (!pginfos[i].busy_proc_ent) {
1389 printk("pktgen: Error: cannot create net/%s/pg_busy procfs entry.\n", PG_PROC_DIR);
1392 pginfos[i].busy_proc_ent->read_proc = proc_busy_read;
1393 pginfos[i].busy_proc_ent->data = (void*)(long)(i);
1398 for (i = 0; i<MAX_PKTGEN; i++) {
1399 if (strlen(pginfos[i].fname)) {
1400 remove_proc_entry(pginfos[i].fname, NULL);
1402 if (strlen(pginfos[i].busy_fname)) {
1403 remove_proc_entry(pginfos[i].busy_fname, NULL);
1410 static void __exit cleanup(void)
1413 for (i = 0; i<MAX_PKTGEN; i++) {
1414 if (strlen(pginfos[i].fname)) {
1415 remove_proc_entry(pginfos[i].fname, NULL);
1417 if (strlen(pginfos[i].busy_fname)) {
1418 remove_proc_entry(pginfos[i].busy_fname, NULL);
1425 module_exit(cleanup);
1427 MODULE_AUTHOR("Robert Olsson <robert.olsson@its.uu.se");
1428 MODULE_DESCRIPTION("Packet Generator tool");
1429 MODULE_LICENSE("GPL");
1430 module_param(count_d, int, 0);
1431 module_param(ipg_d, int, 0);
1432 module_param(cpu_speed, int, 0);
1433 module_param(clone_skb_d, int, 0);