linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Ben Greear <greearb@candelatech.com>
To: linux-kernel <linux-kernel@vger.kernel.org>,
	"David S. Miller" <davem@redhat.com>
Subject: PATCH:  pktgen.c update
Date: Sat, 20 Apr 2002 17:42:21 -0700	[thread overview]
Message-ID: <3CC20AED.4000007@candelatech.com> (raw)

[-- Attachment #1: Type: text/plain, Size: 582 bytes --]

I got all excited about the pktgen.c module, and went in and
changed it significantly to suite my needs better.  I would
be happy to see these changes integrated into the mainstream kernel,
but even if that is not appropriate, I will appreciate any
feedback, especially about how to make it sleep more efficiently
when there is an inter-packet-gap set.

Thanks,
Ben

-- 
Ben Greear <greearb@candelatech.com>       <Ben_Greear AT excite.com>
President of Candela Technologies Inc      http://www.candelatech.com
ScryMUD:  http://scry.wanfear.com     http://scry.wanfear.com/~greear


[-- Attachment #2: patch2.txt --]
[-- Type: text/plain, Size: 39588 bytes --]

--- linux/net/core/pktgen.c	Sat Apr 20 17:28:52 2002
+++ linux.dev/net/core/pktgen.c	Sat Apr 20 17:27:55 2002
@@ -1,4 +1,5 @@
-/* $Id: pktgen.c,v 1.1.2.1 2002/03/01 12:15:05 davem Exp $
+/* -*-linux-c-*-
+ * $Id: pktgen.c,v 1.1.2.1 2002/03/01 12:15:05 davem Exp $
  * pktgen.c: Packet Generator for performance evaluation.
  *
  * Copyright 2001, 2002 by Robert Olsson <robert.olsson@its.uu.se>
@@ -18,6 +19,20 @@
  * MAC address typo fixed. 010417 --ro
  * Integrated.  020301 --DaveM
  * Added multiskb option 020301 --DaveM
+ * Significant re-work of the module:
+ *   *  Updated to support generation over multiple interfaces at once
+ *       by creating 32 /proc/net/pg* files.  Each file can be manipulated
+ *       individually.
+ *   *  Converted many counters to __u64 to allow longer runs.
+ *   *  Allow configuration of ranges, like min/max IP address, MACs,
+ *       and UDP-ports, for both source and destination, and can
+ *       set to use a random distribution or sequentially walk the range.
+ *   *  Can now change some values after starting.
+ *   *  Place 12-byte packet in UDP payload with magic number,
+ *       sequence number, and timestamp.  Will write receiver next.
+ *   *  The new changes seem to have a performance inpact of around 1%,
+ *       as far as I can tell.
+ *   --Ben Greear <greearb@candelatech.com>
  *
  * See Documentation/networking/pktgen.txt for how to use this.
  */
@@ -56,69 +71,189 @@
 #define cycles()	((u32)get_cycles())
 
 static char version[] __initdata = 
-  "pktgen.c: v1.0 010812: Packet Generator for packet performance testing.\n";
+  "pktgen.c: v1.1: Packet Generator for packet performance testing.\n";
 
-/* Parameters */
-static char pg_outdev[32], pg_dst[32];
-static int pkt_size = ETH_ZLEN;
-static int nfrags = 0;
-static __u32 pg_count = 100000;  /* Default No packets to send */
-static __u32 pg_ipg = 0;  /* Default Interpacket gap in nsec */
-static int pg_multiskb = 0; /* Use multiple SKBs during packet gen. */
+/* Used to help with determining the pkts on receive */
+#define PKTGEN_MAGIC 0xbe9be955
 
-static int debug;
-static int forced_stop;
-static int pg_cpu_speed;
-static int pg_busy;
+/* Keep information per interface */
+struct pktgen_info {
+        /* Parameters */
+
+        /* If min != max, then we will either do a linear iteration, or
+         * we will do a random selection from within the range.
+         */
+        __u32 flags;     /* 1<<0 IP-Src Random, 1<<1 IP-Dst Random,
+                          * 1<<2 UDP-Src Random, 1<<3 UDP-Dst Random
+                          * 1<<4 MAC-Src Random, 1<<5 MAC-Dst Random
+                          * 1<<6 Specify-Src-Mac (default is to use Interface's MAC Addr)
+                          * 1<<7 Specify-Src-IP (default is to use Interface's IP Addr)
+                          */
+        
+        int pkt_size;    /* = ETH_ZLEN; */
+        int nfrags;
+        __u32 pg_ipg;    /* Default Interpacket gap in nsec */
+        __u64 pg_count;  /* Default No packets to send */
+        __u64 pg_sofar;  /* How many pkts we've sent so far */
+        __u64 errors;    /* Errors when trying to transmit, pkts will be re-sent */
+        struct timeval started_at;
+        struct timeval stopped_at;
+        __u64 idle_acc;
+        __u32 seq_num;
+        
+        int pg_multiskb; /* Use multiple SKBs during packet gen. */
+        int forced_stop;
+        int pg_busy;
+        int do_run_run;  /* if this changes to false, the test will stop */
+        
+        char pg_outdev[32];
+        char dst_min[32];
+        char dst_max[32];
+        char src_min[32];
+        char src_max[32];
+
+        /* If we're doing ranges, random or incremental, then this
+         * defines the min/max for those ranges.
+         */
+        __u32 saddr_min; /* inclusive, source IP address */
+        __u32 saddr_max; /* exclusive, source IP address */
+        __u32 daddr_min; /* inclusive, dest IP address */
+        __u32 daddr_max; /* exclusive, dest IP address */
+
+        __u16 udp_src_min; /* inclusive, source UDP port */
+        __u16 udp_src_max; /* exclusive, source UDP port */
+        __u16 udp_dst_min; /* inclusive, dest UDP port */
+        __u16 udp_dst_max; /* exclusive, dest UDP port */
+
+        __u32 src_mac_count; /* How many MACs to iterate through */
+        __u32 dst_mac_count; /* How many MACs to iterate through */
+        
+        unsigned char dst_mac[6];
+        unsigned char src_mac[6];
+        
+        __u32 cur_dst_mac_offset;
+        __u32 cur_src_mac_offset;
+        __u32 cur_saddr;
+        __u32 cur_daddr;
+        __u16 cur_udp_dst;
+        __u16 cur_udp_src;
+        
+        __u8 hh[14];
+        /* = { 
+           0x00, 0x80, 0xC8, 0x79, 0xB3, 0xCB, 
+           
+           We fill in SRC address later
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x08, 0x00
+           };
+        */
+        __u16 pad; /* pad out the hh struct to an even 16 bytes */
+        char pg_result[512];
+
+        /* proc file names */
+        char fname[80];
+        char busy_fname[80];
 
-static __u8 hh[14] = { 
-    0x00, 0x80, 0xC8, 0x79, 0xB3, 0xCB, 
+        struct proc_dir_entry *pg_proc_ent;
+        struct proc_dir_entry *pg_busy_proc_ent;
+};
 
-    /* We fill in SRC address later */
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x08, 0x00
+struct pktgen_hdr {
+        __u32 pgh_magic;
+        __u32 seq_num;
+        struct timeval timestamp;
 };
 
-static unsigned char *pg_dstmac = hh;
-static char pg_result[512];
+static int pg_cpu_speed;
+static int debug;
+
+/* Module parameters, defaults. */
+static int pg_count_d = 100000;
+static int pg_ipg_d = 0;
+static int pg_multiskb_d = 0;
+
+
+#define MAX_PKTGEN 32
+static struct pktgen_info pginfos[MAX_PKTGEN];
+
+
+/** Convert to miliseconds */
+inline __u64 tv_to_ms(const struct timeval* tv) {
+        __u64 ms = tv->tv_usec / 1000;
+        ms += (__u64)tv->tv_sec * (__u64)1000;
+        return ms;
+}
+
+inline __u64 getCurMs(void) {
+        struct timeval tv;
+        do_gettimeofday(&tv);
+        return tv_to_ms(&tv);
+}
+
 
-static struct net_device *pg_setup_inject(u32 *saddrp)
+static struct net_device *pg_setup_inject(struct pktgen_info* info)
 {
 	struct net_device *odev;
-	int p1, p2;
-	u32 saddr;
 
 	rtnl_lock();
-	odev = __dev_get_by_name(pg_outdev);
+	odev = __dev_get_by_name(info->pg_outdev);
 	if (!odev) {
-		sprintf(pg_result, "No such netdevice: \"%s\"", pg_outdev);
+		sprintf(info->pg_result, "No such netdevice: \"%s\"", info->pg_outdev);
 		goto out_unlock;
 	}
 
 	if (odev->type != ARPHRD_ETHER) {
-		sprintf(pg_result, "Not ethernet device: \"%s\"", pg_outdev);
+		sprintf(info->pg_result, "Not ethernet device: \"%s\"", info->pg_outdev);
 		goto out_unlock;
 	}
 
 	if (!netif_running(odev)) {
-		sprintf(pg_result, "Device is down: \"%s\"", pg_outdev);
+		sprintf(info->pg_result, "Device is down: \"%s\"", info->pg_outdev);
 		goto out_unlock;
 	}
 
-	for (p1 = 6, p2 = 0; p1 < odev->addr_len + 6; p1++)
-		hh[p1] = odev->dev_addr[p2++];
-
-	saddr = 0;
-	if (odev->ip_ptr) {
-		struct in_device *in_dev = odev->ip_ptr;
-
-		if (in_dev->ifa_list)
-			saddr = in_dev->ifa_list->ifa_address;
-	}
+        /* Default to the interface's mac if not explicitly set. */
+        if (!(info->flags & (1<<6))) {
+                memcpy(&(info->hh[6]), odev->dev_addr, 6);
+        }
+        else {
+                memcpy(&(info->hh[6]), info->src_mac, 6);
+        }
+
+        /* Set up Dest MAC */
+        memcpy(&(info->hh[0]), info->dst_mac, 6);
+        
+	info->saddr_min = 0;
+	info->saddr_max = 0;
+        if (strlen(info->src_min) == 0) {
+                if (odev->ip_ptr) {
+                        struct in_device *in_dev = odev->ip_ptr;
+
+                        if (in_dev->ifa_list) {
+                                info->saddr_min = in_dev->ifa_list->ifa_address;
+                                info->saddr_max = info->saddr_min;
+                        }
+                }
+	}
+        else {
+                info->saddr_min = in_aton(info->src_min);
+                info->saddr_max = in_aton(info->src_max);
+        }
+
+        info->daddr_min = in_aton(info->dst_min);
+        info->daddr_max = in_aton(info->dst_max);
+
+        /* Initialize current values. */
+        info->cur_dst_mac_offset = 0;
+        info->cur_src_mac_offset = 0;
+        info->cur_saddr = info->saddr_min;
+        info->cur_daddr = info->daddr_min;
+        info->cur_udp_dst = info->udp_dst_min;
+        info->cur_udp_src = info->udp_src_min;
+        
 	atomic_inc(&odev->refcnt);
 	rtnl_unlock();
 
-	*saddrp = saddr;
 	return odev;
 
 out_unlock:
@@ -126,9 +261,7 @@
 	return NULL;
 }
 
-static u32 idle_acc_lo, idle_acc_hi;
-
-static void nanospin(int pg_ipg)
+static void nanospin(int pg_ipg, struct pktgen_info* info)
 {
 	u32 idle_start, idle;
 
@@ -140,9 +273,7 @@
 		if (idle * 1000 >= pg_ipg * pg_cpu_speed)
 			break;
 	}
-	idle_acc_lo += idle;
-	if (idle_acc_lo < idle)
-		idle_acc_hi++;
+	info->idle_acc += idle;
 }
 
 static int calc_mhz(void)
@@ -173,17 +304,136 @@
 	}
 }
 
-static struct sk_buff *fill_packet(struct net_device *odev, __u32 saddr)
+
+/* Increment/randomize headers according to flags and current values
+ * for IP src/dest, UDP src/dst port, MAC-Addr src/dst
+ */
+static void mod_cur_headers(struct pktgen_info* info) {        
+        __u32 imn;
+        __u32 imx;
+        
+	/*  Deal with source MAC */
+        if (info->src_mac_count > 1) {
+                __u32 mc;
+                __u32 tmp;
+                if (info->flags & (1<<4)) {
+                        mc = net_random() % (info->src_mac_count);
+                }
+                else {
+                        mc = info->cur_src_mac_offset++;
+                        if (info->cur_src_mac_offset > info->src_mac_count) {
+                                info->cur_src_mac_offset = 0;
+                        }
+                }
+
+                tmp = info->src_mac[5] + (mc & 0xFF);
+                info->hh[11] = tmp;
+                tmp = (info->src_mac[4] + ((mc >> 8) & 0xFF) + (tmp >> 8));
+                info->hh[10] = tmp;
+                tmp = (info->src_mac[3] + ((mc >> 16) & 0xFF) + (tmp >> 8));
+                info->hh[9] = tmp;
+                tmp = (info->src_mac[2] + ((mc >> 24) & 0xFF) + (tmp >> 8));
+                info->hh[8] = tmp;
+                tmp = (info->src_mac[1] + (tmp >> 8));
+                info->hh[7] = tmp;        
+        }
+
+        /*  Deal with Destination MAC */
+        if (info->dst_mac_count > 1) {
+                __u32 mc;
+                __u32 tmp;
+                if (info->flags & (1<<5)) {
+                        mc = net_random() % (info->dst_mac_count);
+                }
+                else {
+                        mc = info->cur_dst_mac_offset++;
+                        if (info->cur_dst_mac_offset > info->dst_mac_count) {
+                                info->cur_dst_mac_offset = 0;
+                        }
+                }
+
+                tmp = info->dst_mac[5] + (mc & 0xFF);
+                info->hh[5] = tmp;
+                tmp = (info->dst_mac[4] + ((mc >> 8) & 0xFF) + (tmp >> 8));
+                info->hh[4] = tmp;
+                tmp = (info->dst_mac[3] + ((mc >> 16) & 0xFF) + (tmp >> 8));
+                info->hh[3] = tmp;
+                tmp = (info->dst_mac[2] + ((mc >> 24) & 0xFF) + (tmp >> 8));
+                info->hh[2] = tmp;
+                tmp = (info->dst_mac[1] + (tmp >> 8));
+                info->hh[1] = tmp;        
+        }
+
+        if (info->udp_src_min < info->udp_src_max) {
+                if (info->flags & (1<<2)) {
+                        info->cur_udp_src = ((net_random() % (info->udp_src_max - info->udp_src_min))
+                                             + info->udp_src_min);
+                }
+                else {
+                     info->cur_udp_src++;
+                     if (info->cur_udp_src >= info->udp_src_max) {
+                             info->cur_udp_src = info->udp_src_min;
+                     }
+                }
+        }
+
+        if (info->udp_dst_min < info->udp_dst_max) {
+                if (info->flags & (1<<3)) {
+                        info->cur_udp_dst = ((net_random() % (info->udp_dst_max - info->udp_dst_min))
+                                             + info->udp_dst_min);
+                }
+                else {
+                     info->cur_udp_dst++;
+                     if (info->cur_udp_dst >= info->udp_dst_max) {
+                             info->cur_udp_dst = info->udp_dst_min;
+                     }
+                }
+        }
+
+        if ((imn = ntohl(info->saddr_min)) < (imx = ntohl(info->saddr_max))) {
+                __u32 t;
+                if (info->flags & (1<<0)) {
+                        t = ((net_random() % (imx - imn)) + imn);
+                }
+                else {
+                     t = ntohl(info->cur_saddr);
+                     t++;
+                     if (t >= imx) {
+                             t = imn;
+                     }
+                }
+                info->cur_saddr = htonl(t);
+        }
+
+        if ((imn = ntohl(info->daddr_min)) < (imx = ntohl(info->daddr_max))) {
+                __u32 t;
+                if (info->flags & (1<<1)) {
+                        t = ((net_random() % (imx - imn)) + imn);
+                }
+                else {
+                     t = ntohl(info->cur_daddr);
+                     t++;
+                     if (t >= imx) {
+                             t = imn;
+                     }
+                }
+                info->cur_daddr = htonl(t);
+        }
+}/* mod_cur_headers */
+
+
+static struct sk_buff *fill_packet(struct net_device *odev, struct pktgen_info* info)
 {
-	struct sk_buff *skb;
+	struct sk_buff *skb = NULL;
 	__u8 *eth;
 	struct udphdr *udph;
 	int datalen, iplen;
 	struct iphdr *iph;
-
-	skb = alloc_skb(pkt_size + 64 + 16, GFP_ATOMIC);
+        struct pktgen_hdr *pgh = NULL;
+        
+	skb = alloc_skb(info->pkt_size + 64 + 16, GFP_ATOMIC);
 	if (!skb) {
-		sprintf(pg_result, "No memory");
+		sprintf(info->pg_result, "No memory");
 		return NULL;
 	}
 
@@ -194,15 +444,20 @@
 	iph = (struct iphdr *)skb_put(skb, sizeof(struct iphdr));
 	udph = (struct udphdr *)skb_put(skb, sizeof(struct udphdr));
 
-	/*  Copy the ethernet header  */
-	memcpy(eth, hh, 14);
-
-	datalen = pkt_size - 14 - 20 - 8; /* Eth + IPh + UDPh */
-	if (datalen < 0)
-		datalen = 0;
-
-	udph->source = htons(9);
-	udph->dest = htons(9);
+        /* Update any of the values, used when we're incrementing various
+         * fields.
+         */
+        mod_cur_headers(info);
+
+	memcpy(eth, info->hh, 14);
+        
+	datalen = info->pkt_size - 14 - 20 - 8; /* Eth + IPh + UDPh */
+	if (datalen < sizeof(struct pktgen_hdr)) {
+		datalen = sizeof(struct pktgen_hdr);
+        }
+        
+	udph->source = htons(info->cur_udp_src);
+	udph->dest = htons(info->cur_udp_dst);
 	udph->len = htons(datalen + 8); /* DATA + udphdr */
 	udph->check = 0;  /* No checksum */
 
@@ -211,8 +466,8 @@
 	iph->ttl = 3;
 	iph->tos = 0;
 	iph->protocol = IPPROTO_UDP; /* UDP */
-	iph->saddr = saddr;
-	iph->daddr = in_aton(pg_dst);
+	iph->saddr = info->cur_saddr;
+	iph->daddr = info->cur_daddr;
 	iph->frag_off = 0;
 	iplen = 20 + 8 + datalen;
 	iph->tot_len = htons(iplen);
@@ -223,12 +478,15 @@
 	skb->dev = odev;
 	skb->pkt_type = PACKET_HOST;
 
-	if (nfrags <= 0) {
-		skb_put(skb, datalen);
+	if (info->nfrags <= 0) {
+                pgh = (struct pktgen_hdr *)skb_put(skb, datalen);
 	} else {
-		int frags = nfrags;
+		int frags = info->nfrags;
 		int i;
 
+                /* TODO: Verify this is OK...it sure is ugly. --Ben */
+                pgh = (struct pktgen_hdr*)(((char*)(udph)) + 8);
+                
 		if (frags > MAX_SKB_FRAGS)
 			frags = MAX_SKB_FRAGS;
 		if (datalen > frags*PAGE_SIZE) {
@@ -272,63 +530,95 @@
 		}
 	}
 
+        /* Stamp the time, and sequence number, convert them to network byte order */
+        if (pgh) {
+                pgh->pgh_magic = __constant_htonl(PKTGEN_MAGIC);
+                do_gettimeofday(&(pgh->timestamp));
+                pgh->timestamp.tv_usec = htonl(pgh->timestamp.tv_usec);
+                pgh->timestamp.tv_sec = htonl(pgh->timestamp.tv_sec);
+                pgh->seq_num = htonl(info->seq_num);
+        }
+        
 	return skb;
 }
 
 
-static void pg_inject(void)
+static void pg_inject(struct pktgen_info* info)
 {
-	u32 saddr;
 	struct net_device *odev;
-	struct sk_buff *skb;
-	struct timeval start, stop;
-	u32 total, idle;
-	int pc, lcount;
-
-	odev = pg_setup_inject(&saddr);
+	struct sk_buff *skb = NULL;
+	__u64 total = 0;
+        __u64 idle = 0;
+	__u64 lcount = 0;
+        int nr_frags = 0;
+        
+	odev = pg_setup_inject(info);
 	if (!odev)
 		return;
 
-	skb = fill_packet(odev, saddr);
-	if (skb == NULL)
-		goto out_reldev;
-
-	forced_stop = 0;
-	idle_acc_hi = 0;
-	idle_acc_lo = 0;
-	pc = 0;
-	lcount = pg_count;
-	do_gettimeofday(&start);
-
-	for(;;) {
+        info->do_run_run = 1; /* Cranke yeself! */
+	info->forced_stop = 0;
+	info->idle_acc = 0;
+	info->pg_sofar = 0;
+	lcount = info->pg_count;
+	do_gettimeofday(&(info->started_at));
+
+	while(info->do_run_run) {
+                /* Want to set a time-stamp, so build a new pkt each time */
+                if (skb) {
+                        kfree_skb(skb);
+                }
+                skb = fill_packet(odev, info);
+                if (skb == NULL)
+                   goto out_reldev;
+                nr_frags = skb_shinfo(skb)->nr_frags;
+                   
 		spin_lock_bh(&odev->xmit_lock);
 		if (!netif_queue_stopped(odev)) {
 			struct sk_buff *skb2 = skb;
 
-			if (pg_multiskb)
+			if (info->pg_multiskb)
 				skb2 = skb_copy(skb, GFP_ATOMIC);
 			else
 				atomic_inc(&skb->users);
 			if (!skb2)
 				goto skip;
 			if (odev->hard_start_xmit(skb2, odev)) {
-				kfree_skb(skb2);
-				if (net_ratelimit())
-					printk(KERN_INFO "Hard xmit error\n");
+				if (net_ratelimit()) {
+                                   printk(KERN_INFO "Hard xmit error\n");
+                                }
+                                info->errors++;
 			}
-			pc++;
+                        else {
+                           info->pg_sofar++;
+                           info->seq_num++;
+                        }
 		}
 	skip:
 		spin_unlock_bh(&odev->xmit_lock);
 
-		if (pg_ipg)
-			nanospin(pg_ipg);
-		if (forced_stop)
+		if (info->pg_ipg) {
+                        /* Try not to busy-spin if we have larger sleep times.
+                         * TODO:  Investigate better ways to do this.
+                         */
+                        if (info->pg_ipg < 10000) { /* 10 usecs or less */
+                                nanospin(info->pg_ipg, info);
+                        }
+                        else if (info->pg_ipg < 10000000) { /* 10ms or less */
+                                udelay(info->pg_ipg / 1000);
+                        }
+                        else {
+                                mdelay(info->pg_ipg / 1000000);
+                        }
+                }
+                
+		if (info->forced_stop)
 			goto out_intr;
 		if (signal_pending(current))
-			goto out_intr;
+                        break;
 
-		if (--lcount == 0) {
+                /* If lcount is zero, then run forever */
+		if ((lcount != 0) && (--lcount == 0)) {
 			if (atomic_read(&skb->users) != 1) {
 				u32 idle_start, idle;
 
@@ -339,9 +629,7 @@
 					schedule();
 				}
 				idle = cycles() - idle_start;
-				idle_acc_lo += idle;
-				if (idle_acc_lo < idle)
-					idle_acc_hi++;
+				info->idle_acc += idle;
 			}
 			break;
 		}
@@ -361,53 +649,63 @@
 					do_softirq();
 			} while (netif_queue_stopped(odev));
 			idle = cycles() - idle_start;
-			idle_acc_lo += idle;
-			if (idle_acc_lo < idle)
-				idle_acc_hi++;
+			info->idle_acc += idle;
 		}
-	}
+	}/* while we should be running */
 
-	do_gettimeofday(&stop);
+	do_gettimeofday(&(info->stopped_at));
 
-	total = (stop.tv_sec - start.tv_sec) * 1000000 +
-		stop.tv_usec - start.tv_usec;
+	total = (info->stopped_at.tv_sec - info->started_at.tv_sec) * 1000000 +
+		info->stopped_at.tv_usec - info->started_at.tv_usec;
 
-	idle = (((idle_acc_hi<<20)/pg_cpu_speed)<<12)+idle_acc_lo/pg_cpu_speed;
+	idle = (__u32)(info->idle_acc)/(__u32)(pg_cpu_speed);
 
         {
-		char *p = pg_result;
-    
-		p += sprintf(p, "OK: %u(c%u+d%u) usec, %u (%dbyte,%dfrags) %upps %uMB/sec",
+		char *p = info->pg_result;
+                __u64 pps = (__u32)(info->pg_sofar * 1000) / ((__u32)(total) / 1000);
+                __u64 bps = pps * 8 * (info->pkt_size + 4); /* take 32bit ethernet CRC into account */
+		p += sprintf(p, "OK: %llu(c%llu+d%llu) usec, %llu (%dbyte,%dfrags) %llupps %lluMb/sec (%llubps)  errors: %llu",
 			     total, total-idle, idle,
-			     pc, skb->len, skb_shinfo(skb)->nr_frags,
-			     ((pc*1000)/(total/1000)),
-			     (((pc*1000)/(total/1000))*pkt_size)/1024/1024
+			     info->pg_sofar,
+                             skb->len + 4, /* Add 4 to account for the ethernet checksum */
+                             nr_frags,
+			     pps,
+			     bps/1024/1024, bps, info->errors
 			     );
 	}
-
+        
 out_relskb:
-	kfree_skb(skb);
+        if (skb) {
+           kfree_skb(skb);
+           skb = NULL;
+        }
+
 out_reldev:
         dev_put(odev);
 	return;
 
 out_intr:
-	sprintf(pg_result, "Interrupted");
+	sprintf(info->pg_result, "Interrupted");
 	goto out_relskb;
 }
 
 /* proc/net/pg */
 
-static struct proc_dir_entry *pg_proc_ent = 0;
-static struct proc_dir_entry *pg_busy_proc_ent = 0;
-
 static int proc_pg_busy_read(char *buf , char **start, off_t offset,
 			     int len, int *eof, void *data)
 {
 	char *p;
+        int idx = (int)(data);
+        struct pktgen_info* info = NULL;
+        
+        if ((idx < 0) || (idx >= MAX_PKTGEN)) {
+                printk("ERROR: idx: %i is out of range in proc_pg_write\n", idx);
+                return -EINVAL;
+        }
+        info = &(pginfos[idx]);
   
 	p = buf;
-	p += sprintf(p, "%d\n", pg_busy);
+	p += sprintf(p, "%d\n", info->pg_busy);
 	*eof = 1;
   
 	return p-buf;
@@ -418,16 +716,72 @@
 {
 	char *p;
 	int i;
+        int idx = (int)(data);
+        struct pktgen_info* info = NULL;
+        __u64 sa;
+        __u64 stopped;
+        __u64 now = getCurMs();
+        
+        if ((idx < 0) || (idx >= MAX_PKTGEN)) {
+                printk("ERROR: idx: %i is out of range in proc_pg_write\n", idx);
+                return -EINVAL;
+        }
+        info = &(pginfos[idx]);
   
 	p = buf;
-	p += sprintf(p, "Params: count=%u pkt_size=%u frags %d ipg %u multiskb %d odev \"%s\" dst %s dstmac ",
-		     pg_count, pkt_size, nfrags, pg_ipg, pg_multiskb,
-		     pg_outdev, pg_dst);
-	for (i = 0; i < 6; i++)
-		p += sprintf(p, "%02X%s", pg_dstmac[i], i == 5 ? "\n" : ":");
-
-	if (pg_result[0])
-		p += sprintf(p, "Result: %s\n", pg_result);
+        p += sprintf(p, "VERSION-1\n"); /* Help with parsing compatibility */
+	p += sprintf(p, "Params: count %llu  pkt_size: %u  frags: %d  ipg: %u  multiskb: %d odev \"%s\"\n",
+		     info->pg_count, info->pkt_size, info->nfrags, info->pg_ipg,
+                     info->pg_multiskb, info->pg_outdev);
+        p += sprintf(p, "     dst_min: %s  dst_max: %s  src_min: %s  src_max: %s\n",
+                     info->dst_min, info->dst_max, info->src_min, info->src_max);
+        p += sprintf(p, "     src_mac: ");
+	for (i = 0; i < 6; i++) {
+		p += sprintf(p, "%02X%s", info->src_mac[i], i == 5 ? "  " : ":");
+        }
+        p += sprintf(p, "dst_mac: ");
+	for (i = 0; i < 6; i++) {
+		p += sprintf(p, "%02X%s", info->dst_mac[i], i == 5 ? "\n" : ":");
+        }
+        p += sprintf(p, "     udp_src_min: %d  udp_src_max: %d  udp_dst_min: %d  udp_dst_max: %d\n",
+                     info->udp_src_min, info->udp_src_max, info->udp_dst_min,
+                     info->udp_dst_max);
+        p += sprintf(p, "     src_mac_count: %d  dst_mac_count: %d\n     Flags: ",
+                     info->src_mac_count, info->dst_mac_count);
+        if (info->flags & (1<<0)) {
+                p += sprintf(p, "IPSRC_RND  ");
+        }
+        if (info->flags & (1<<1)) {
+                p += sprintf(p, "IPDST_RND  ");
+        }
+        if (info->flags & (1<<2)) {
+                p += sprintf(p, "UDPSRC_RND  ");
+        }
+        if (info->flags & (1<<3)) {
+                p += sprintf(p, "UDPDST_RND  ");
+        }
+        if (info->flags & (1<<4)) {
+                p += sprintf(p, "MACSRC_RND  ");
+        }
+        if (info->flags & (1<<5)) {
+                p += sprintf(p, "MACDST_RND  ");
+        }
+        p += sprintf(p, "\n");
+        
+        sa = tv_to_ms(&(info->started_at));
+        stopped = tv_to_ms(&(info->stopped_at));
+        if (info->do_run_run) {
+                stopped = now; /* not really stopped, more like last-running-at */
+        }
+        p += sprintf(p, "Current:\n     pkts-sofar: %llu  errors: %llu\n     started: %llums  stopped: %llums  now: %llums  idle: %lluns\n",
+                     info->pg_sofar, info->errors, sa, stopped, now, info->idle_acc);
+        p += sprintf(p, "     seq_num: %d  cur_dst_mac_offset: %d  cur_src_mac_offset: %d\n",
+                     info->seq_num, info->cur_dst_mac_offset, info->cur_src_mac_offset);
+        p += sprintf(p, "     cur_saddr: 0x%x  cur_daddr: 0x%x  cur_udp_dst: %d  cur_udp_src: %d\n",
+                     info->cur_saddr, info->cur_daddr, info->cur_udp_dst, info->cur_udp_src);
+        
+	if (info->pg_result[0])
+		p += sprintf(p, "Result: %s\n", info->pg_result);
 	else
 		p += sprintf(p, "Result: Idle\n");
 	*eof = 1;
@@ -498,7 +852,17 @@
 	int i = 0, max, len;
 	char name[16], valstr[32];
 	unsigned long value = 0;
-  
+        int idx = (int)(data);
+        struct pktgen_info* info = NULL;
+        char* pg_result = NULL;
+        
+        if ((idx < 0) || (idx >= MAX_PKTGEN)) {
+                printk("ERROR: idx: %i is out of range in proc_pg_write\n", idx);
+                return -EINVAL;
+        }
+        info = &(pginfos[idx]);
+        pg_result = &(info->pg_result[0]);
+        
 	if (count < 1) {
 		sprintf(pg_result, "Wrong command format");
 		return -EINVAL;
@@ -521,85 +885,206 @@
 	if (debug)
 		printk("pg: %s,%lu\n", name, count);
 
-	/* Only stop is allowed when we are running */
-  
 	if (!strcmp(name, "stop")) {
-		forced_stop = 1;
-		if (pg_busy)
+		info->forced_stop = 1;
+		if (info->do_run_run) {
 			strcpy(pg_result, "Stopping");
+                }
+                else {
+                        strcpy(pg_result, "Already stopped...\n");
+                }
+                info->do_run_run = 0;
 		return count;
 	}
 
-	if (pg_busy) {
-		strcpy(pg_result, "Busy");
-		return -EINVAL;
-	}
-
 	if (!strcmp(name, "pkt_size")) {
 		len = num_arg(&buffer[i], 10, &value);
 		i += len;
 		if (value < 14+20+8)
 			value = 14+20+8;
-		pkt_size = value;
-		sprintf(pg_result, "OK: pkt_size=%u", pkt_size);
+		info->pkt_size = value;
+		sprintf(pg_result, "OK: pkt_size=%u", info->pkt_size);
 		return count;
 	}
 	if (!strcmp(name, "frags")) {
 		len = num_arg(&buffer[i], 10, &value);
 		i += len;
-		nfrags = value;
-		sprintf(pg_result, "OK: frags=%u", nfrags);
+		info->nfrags = value;
+		sprintf(pg_result, "OK: frags=%u", info->nfrags);
 		return count;
 	}
 	if (!strcmp(name, "ipg")) {
 		len = num_arg(&buffer[i], 10, &value);
 		i += len;
-		pg_ipg = value;
-		sprintf(pg_result, "OK: ipg=%u", pg_ipg);
+		info->pg_ipg = value;
+		sprintf(pg_result, "OK: ipg=%u", info->pg_ipg);
+		return count;
+	}
+ 	if (!strcmp(name, "udp_src_min")) {
+		len = num_arg(&buffer[i], 10, &value);
+		i += len;
+	 	info->udp_src_min = value;
+		sprintf(pg_result, "OK: udp_src_min=%u", info->udp_src_min);
+		return count;
+	}
+ 	if (!strcmp(name, "udp_dst_min")) {
+		len = num_arg(&buffer[i], 10, &value);
+		i += len;
+	 	info->udp_dst_min = value;
+		sprintf(pg_result, "OK: udp_dst_min=%u", info->udp_dst_min);
+		return count;
+	}
+ 	if (!strcmp(name, "udp_src_max")) {
+		len = num_arg(&buffer[i], 10, &value);
+		i += len;
+	 	info->udp_src_max = value;
+		sprintf(pg_result, "OK: udp_src_max=%u", info->udp_src_max);
+		return count;
+	}
+ 	if (!strcmp(name, "udp_dst_max")) {
+		len = num_arg(&buffer[i], 10, &value);
+		i += len;
+	 	info->udp_dst_max = value;
+		sprintf(pg_result, "OK: udp_dst_max=%u", info->udp_dst_max);
 		return count;
 	}
 	if (!strcmp(name, "multiskb")) {
 		len = num_arg(&buffer[i], 10, &value);
 		i += len;
-		pg_multiskb = (value ? 1 : 0);
-		sprintf(pg_result, "OK: multiskb=%d", pg_multiskb);
+		info->pg_multiskb = (value ? 1 : 0);
+		sprintf(pg_result, "OK: multiskb=%d", info->pg_multiskb);
 		return count;
 	}
 	if (!strcmp(name, "count")) {
 		len = num_arg(&buffer[i], 10, &value);
 		i += len;
-		pg_count = value;
-		sprintf(pg_result, "OK: count=%u", pg_count);
+		info->pg_count = value;
+		sprintf(pg_result, "OK: count=%llu", info->pg_count);
+		return count;
+	}
+	if (!strcmp(name, "src_mac_count")) {
+		len = num_arg(&buffer[i], 10, &value);
+		i += len;
+		info->src_mac_count = value;
+		sprintf(pg_result, "OK: src_mac_count=%d", info->src_mac_count);
+		return count;
+	}
+	if (!strcmp(name, "dst_mac_count")) {
+		len = num_arg(&buffer[i], 10, &value);
+		i += len;
+		info->dst_mac_count = value;
+		sprintf(pg_result, "OK: dst_mac_count=%d", info->dst_mac_count);
 		return count;
 	}
 	if (!strcmp(name, "odev")) {
-		len = strn_len(&buffer[i], sizeof(pg_outdev) - 1);
-		memset(pg_outdev, 0, sizeof(pg_outdev));
-		strncpy(pg_outdev, &buffer[i], len);
+		len = strn_len(&buffer[i], sizeof(info->pg_outdev) - 1);
+		memset(info->pg_outdev, 0, sizeof(info->pg_outdev));
+		strncpy(info->pg_outdev, &buffer[i], len);
+		i += len;
+		sprintf(pg_result, "OK: odev=%s", info->pg_outdev);
+		return count;
+	}
+	if (!strcmp(name, "flag")) {
+                char f[32];
+                memset(f, 0, 32);
+		len = strn_len(&buffer[i], sizeof(f) - 1);
+		strncpy(f, &buffer[i], len);
 		i += len;
-		sprintf(pg_result, "OK: odev=%s", pg_outdev);
+                if (strcmp(f, "IPSRC_RND") == 0) {
+                        info->flags |= (1<<0);
+                }
+                else if (strcmp(f, "!IPSRC_RND") == 0) {
+                        info->flags &= ~(1<<0);
+                }
+                else if (strcmp(f, "IPDST_RND") == 0) {
+                        info->flags |= (1<<1);
+                }
+                else if (strcmp(f, "!IPDST_RND") == 0) {
+                        info->flags &= ~(1<<1);
+                }
+                else if (strcmp(f, "UDPSRC_RND") == 0) {
+                        info->flags |= (1<<2);
+                }
+                else if (strcmp(f, "!UDPSRC_RND") == 0) {
+                        info->flags &= ~(1<<2);
+                }
+                else if (strcmp(f, "UDPDST_RND") == 0) {
+                        info->flags |= (1<<3);
+                }
+                else if (strcmp(f, "!UDPDST_RND") == 0) {
+                        info->flags &= ~(1<<3);
+                }
+                else if (strcmp(f, "MACSRC_RND") == 0) {
+                        info->flags |= (1<<4);
+                }
+                else if (strcmp(f, "!MACSRC_RND") == 0) {
+                        info->flags &= ~(1<<4);
+                }
+                else if (strcmp(f, "MACDST_RND") == 0) {
+                        info->flags |= (1<<5);
+                }
+                else if (strcmp(f, "!MACDST_RND") == 0) {
+                        info->flags &= ~(1<<5);
+                }
+                else {
+                        sprintf(pg_result, "Flag -:%s:- unknown\nAvailable flags, (prepend ! to un-set flag):\n%s",
+                                f,
+                                "IPSRC_RND, IPDST_RND, UDPSRC_RND, UDPDST_RND, MACSRC_RND, MACDST_RND\n");
+                        return count;
+                }
+		sprintf(pg_result, "OK: flags=0x%x", info->flags);
 		return count;
 	}
-	if (!strcmp(name, "dst")) {
-		len = strn_len(&buffer[i], sizeof(pg_dst) - 1);
-		memset(pg_dst, 0, sizeof(pg_dst));
-		strncpy(pg_dst, &buffer[i], len);
+	if (!strcmp(name, "dst_min") || !strcmp(name, "dst")) {
+		len = strn_len(&buffer[i], sizeof(info->dst_min) - 1);
+		memset(info->dst_min, 0, sizeof(info->dst_min));
+		strncpy(info->dst_min, &buffer[i], len);
 		if(debug)
-			printk("pg: dst set to: %s\n", pg_dst);
+			printk("pg: dst_min set to: %s\n", info->dst_min);
 		i += len;
-		sprintf(pg_result, "OK: dst=%s", pg_dst);
+		sprintf(pg_result, "OK: dst_min=%s", info->dst_min);
+		return count;
+	}
+	if (!strcmp(name, "dst_max")) {
+		len = strn_len(&buffer[i], sizeof(info->dst_max) - 1);
+		memset(info->dst_max, 0, sizeof(info->dst_max));
+		strncpy(info->dst_max, &buffer[i], len);
+		if(debug)
+			printk("pg: dst_max set to: %s\n", info->dst_max);
+		i += len;
+		sprintf(pg_result, "OK: dst_max=%s", info->dst_max);
+		return count;
+	}
+	if (!strcmp(name, "src_min")) {
+		len = strn_len(&buffer[i], sizeof(info->src_min) - 1);
+		memset(info->src_min, 0, sizeof(info->src_min));
+		strncpy(info->src_min, &buffer[i], len);
+		if(debug)
+			printk("pg: src_min set to: %s\n", info->src_min);
+		i += len;
+		sprintf(pg_result, "OK: src_min=%s", info->src_min);
+		return count;
+	}
+	if (!strcmp(name, "src_max")) {
+		len = strn_len(&buffer[i], sizeof(info->src_max) - 1);
+		memset(info->src_max, 0, sizeof(info->src_max));
+		strncpy(info->src_max, &buffer[i], len);
+		if(debug)
+			printk("pg: src_max set to: %s\n", info->src_max);
+		i += len;
+		sprintf(pg_result, "OK: src_max=%s", info->src_max);
 		return count;
 	}
 	if (!strcmp(name, "dstmac")) {
 		char *v = valstr;
-		unsigned char *m = pg_dstmac;
+		unsigned char *m = info->dst_mac;
 
 		len = strn_len(&buffer[i], sizeof(valstr) - 1);
 		memset(valstr, 0, sizeof(valstr));
 		strncpy(valstr, &buffer[i], len);
 		i += len;
 
-		for(*m = 0;*v && m < pg_dstmac + 6; v++) {
+		for(*m = 0;*v && m < info->dst_mac + 6; v++) {
 			if (*v >= '0' && *v <= '9') {
 				*m *= 16;
 				*m += *v - '0';
@@ -620,54 +1105,125 @@
 		sprintf(pg_result, "OK: dstmac");
 		return count;
 	}
+	if (!strcmp(name, "srcmac")) {
+		char *v = valstr;
+		unsigned char *m = info->src_mac;
+
+		len = strn_len(&buffer[i], sizeof(valstr) - 1);
+		memset(valstr, 0, sizeof(valstr));
+		strncpy(valstr, &buffer[i], len);
+		i += len;
+
+		for(*m = 0;*v && m < info->src_mac + 6; v++) {
+			if (*v >= '0' && *v <= '9') {
+				*m *= 16;
+				*m += *v - '0';
+			}
+			if (*v >= 'A' && *v <= 'F') {
+				*m *= 16;
+				*m += *v - 'A' + 10;
+			}
+			if (*v >= 'a' && *v <= 'f') {
+				*m *= 16;
+				*m += *v - 'a' + 10;
+			}
+			if (*v == ':') {
+				m++;
+				*m = 0;
+			}
+		}	  
+		sprintf(pg_result, "OK: srcmac");
+		return count;
+	}
 
 	if (!strcmp(name, "inject") || !strcmp(name, "start")) {
 		MOD_INC_USE_COUNT;
-		pg_busy = 1;
-		strcpy(pg_result, "Starting");
-		pg_inject();
-		pg_busy = 0;
+                if (info->pg_busy) {
+                        strcpy(info->pg_result, "Already running...\n");
+                }
+                else {
+                        info->pg_busy = 1;
+                        strcpy(info->pg_result, "Starting");
+                        pg_inject(info);
+                        info->pg_busy = 0;
+                }
 		MOD_DEC_USE_COUNT;
 		return count;
 	}
 
-	sprintf(pg_result, "No such parameter \"%s\"", name);
+	sprintf(info->pg_result, "No such parameter \"%s\"", name);
 	return -EINVAL;
 }
 
 static int __init pg_init(void)
 {
+        int i;
 	printk(version);
 	cycles_calibrate();
 	if (pg_cpu_speed == 0) {
 		printk("pktgen: Error: your machine does not have working cycle counter.\n");
 		return -EINVAL;
 	}
-	pg_proc_ent = create_proc_entry("net/pg", 0600, 0);
-	if (!pg_proc_ent) {
-		printk("pktgen: Error: cannot create net/pg procfs entry.\n");
-		return -ENOMEM;
-	}
-	pg_proc_ent->read_proc = proc_pg_read;
-	pg_proc_ent->write_proc = proc_pg_write;
-	pg_proc_ent->data = 0;
-
-	pg_busy_proc_ent = create_proc_entry("net/pg_busy", 0, 0);
-	if (!pg_busy_proc_ent) {
-		printk("pktgen: Error: cannot create net/pg_busy procfs entry.\n");
-		remove_proc_entry("net/pg", NULL);
-		return -ENOMEM;
-	}
-	pg_busy_proc_ent->read_proc = proc_pg_busy_read;
-	pg_busy_proc_ent->data = 0;
 
-	return 0;
+        for (i = 0; i<MAX_PKTGEN; i++) {
+                memset(&(pginfos[i]), 0, sizeof(pginfos[i]));
+                pginfos[i].pkt_size = ETH_ZLEN;
+                pginfos[i].nfrags = 0;
+                pginfos[i].pg_multiskb = pg_multiskb_d;
+                pginfos[i].pg_ipg = pg_ipg_d;
+                pginfos[i].pg_count = pg_count_d;
+                pginfos[i].pg_sofar = 0;
+                pginfos[i].hh[12] = 0x08; /* fill in protocol.  Rest is filled in later. */
+                pginfos[i].hh[13] = 0x00;
+                pginfos[i].udp_src_min = 9; /* sink NULL */
+                pginfos[i].udp_src_max = 9;
+                pginfos[i].udp_dst_min = 9;
+                pginfos[i].udp_dst_max = 9;
+                
+                sprintf(pginfos[i].fname, "net/pg%i", i);
+                pginfos[i].pg_proc_ent = create_proc_entry(pginfos[i].fname, 0600, 0);
+                if (!pginfos[i].pg_proc_ent) {
+                        printk("pktgen: Error: cannot create net/pg procfs entry.\n");
+                        goto cleanup_mem;
+                }
+                pginfos[i].pg_proc_ent->read_proc = proc_pg_read;
+                pginfos[i].pg_proc_ent->write_proc = proc_pg_write;
+                pginfos[i].pg_proc_ent->data = (void*)(i);
+
+                sprintf(pginfos[i].busy_fname, "net/pg_busy%i", i);
+                pginfos[i].pg_busy_proc_ent = create_proc_entry(pginfos[i].busy_fname, 0, 0);
+                if (!pginfos[i].pg_busy_proc_ent) {
+                        printk("pktgen: Error: cannot create net/pg_busy procfs entry.\n");
+                        goto cleanup_mem;
+                }
+                pginfos[i].pg_busy_proc_ent->read_proc = proc_pg_busy_read;
+                pginfos[i].pg_busy_proc_ent->data = (void*)(i);
+        }
+        return 0;
+        
+cleanup_mem:
+        for (i = 0; i<MAX_PKTGEN; i++) {
+                if (strlen(pginfos[i].fname)) {
+                        remove_proc_entry(pginfos[i].fname, NULL);
+                }
+                if (strlen(pginfos[i].busy_fname)) {
+                        remove_proc_entry(pginfos[i].busy_fname, NULL);
+                }
+        }
+	return -ENOMEM;
 }
 
 static void __exit pg_cleanup(void)
 {
-	remove_proc_entry("net/pg", NULL);
-	remove_proc_entry("net/pg_busy", NULL);
+        int i;
+        for (i = 0; i<MAX_PKTGEN; i++) {
+                if (strlen(pginfos[i].fname)) {
+                        remove_proc_entry(pginfos[i].fname, NULL);
+                }
+                if (strlen(pginfos[i].busy_fname)) {
+                        remove_proc_entry(pginfos[i].busy_fname, NULL);
+                }
+        }
 }
 
 module_init(pg_init);
@@ -676,7 +1232,7 @@
 MODULE_AUTHOR("Robert Olsson <robert.olsson@its.uu.se");
 MODULE_DESCRIPTION("Packet Generator tool");
 MODULE_LICENSE("GPL");
-MODULE_PARM(pg_count, "i");
-MODULE_PARM(pg_ipg, "i");
+MODULE_PARM(pg_count_d, "i");
+MODULE_PARM(pg_ipg_d, "i");
 MODULE_PARM(pg_cpu_speed, "i");
-MODULE_PARM(pg_multiskb, "i");
+MODULE_PARM(pg_multiskb_d, "i");

[-- Attachment #3: patch1.txt --]
[-- Type: text/plain, Size: 3374 bytes --]

--- linux/Documentation/networking/pktgen.txt	Sat Apr 20 17:28:11 2002
+++ linux.dev/Documentation/networking/pktgen.txt	Sat Apr 20 17:39:55 2002
@@ -4,6 +4,9 @@
    in the place where insmod may find it.
 2. Cut script "ipg" (see below).
 3. Edit script to set preferred device and destination IP address.
+3a.  Create more scripts for different interfaces.  Up to thirty-two
+     pktgen processes can be configured and run at once by using the
+     32 /proc/net/pg* files.
 4. Run in shell: ". ipg"
 5. After this two commands are defined:
    A. "pg" to start generator and to get results.
@@ -12,12 +15,33 @@
       pgset "multiskb 0"      use single SKB for all transmits
       pgset "pkt_size 9014"   sets packet size to 9014
       pgset "frags 5"         packet will consist of 5 fragments
-      pgset "count 200000"    sets number of packets to send
+      pgset "count 200000"    sets number of packets to send, set to zero
+                              for continious sends untill explicitly
+                              stopped.
       pgset "ipg 5000"        sets artificial gap inserted between packets
                               to 5000 nanoseconds
       pgset "dst 10.0.0.1"    sets IP destination address
                               (BEWARE! This generator is very aggressive!)
+      pgset "dst_min 10.0.0.1"            Same as dst
+      pgset "dst_max 10.0.0.254"          Set the maximum destination IP.
+      pgset "src_min 10.0.0.1"            Set the minimum (or only) source IP.
+      pgset "src_max 10.0.0.254"          Set the maximum source IP.
       pgset "dstmac 00:00:00:00:00:00"    sets MAC destination address
+      pgset "srcmac 00:00:00:00:00:00"    sets MAC source address
+      pgset "src_mac_count 1" Sets the number of MACs we'll range through.  The
+                              'minimum' MAC is what you set with srcmac.
+      pgset "dst_mac_count 1" Sets the number of MACs we'll range through.  The
+                              'minimum' MAC is what you set with dstmac.
+      pgset "flag [name]"     Set a flag to determine behaviour.  Current flags
+                              are: IPSRC_RND #IP Source is random (between min/max),
+                                   IPDST_RND, UDPSRC_RND,
+                                   UDPDST_RND, MACSRC_RND, MACDST_RND 
+      pgset "udp_src_min 9"   set UDP source port min, If < udp_src_max, then
+                              cycle through the port range.
+      pgset "udp_src_max 9"   set UDP source port max.
+      pgset "udp_dst_min 9"   set UDP destination port min, If < udp_dst_max, then
+                              cycle through the port range.
+      pgset "udp_dst_max 9"   set UDP destination port max.
       pgset stop    	      aborts injection
       
   Also, ^C aborts generator.
@@ -26,22 +50,24 @@
 
 #! /bin/sh
 
-modprobe pktgen.o
+modprobe pktgen
+
+PGDEV=/proc/net/pg0
 
 function pgset() {
     local result
 
-    echo $1 > /proc/net/pg
+    echo $1 > $PGDEV
 
-    result=`cat /proc/net/pg | fgrep "Result: OK:"`
+    result=`cat $PGDEV | fgrep "Result: OK:"`
     if [ "$result" = "" ]; then
-         cat /proc/net/pg | fgrep Result:
+         cat $PGDEV | fgrep Result:
     fi
 }
 
 function pg() {
-    echo inject > /proc/net/pg
-    cat /proc/net/pg
+    echo inject > $PGDEV
+    cat $PGDEV
 }
 
 pgset "odev eth0"

             reply	other threads:[~2002-04-21  0:42 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2002-04-21  0:42 Ben Greear [this message]
2002-04-21  1:12 ` PATCH: pktgen.c update David S. Miller

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=3CC20AED.4000007@candelatech.com \
    --to=greearb@candelatech.com \
    --cc=davem@redhat.com \
    --cc=linux-kernel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).