patch-2.4.20 linux-2.4.20/net/core/pktgen.c
Next file: linux-2.4.20/net/core/rtnetlink.c
Previous file: linux-2.4.20/net/core/dst.c
Back to the patch index
Back to the overall index
- Lines: 1548
- Date:
Thu Nov 28 15:53:15 2002
- Orig file:
linux-2.4.19/net/core/pktgen.c
- Orig date:
Fri Aug 2 17:39:46 2002
diff -urN linux-2.4.19/net/core/pktgen.c linux-2.4.20/net/core/pktgen.c
@@ -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.8 2002/07/15 19:30:17 robert Exp $
* pktgen.c: Packet Generator for performance evaluation.
*
* Copyright 2001, 2002 by Robert Olsson <robert.olsson@its.uu.se>
@@ -19,6 +20,31 @@
* Integrated. 020301 --DaveM
* Added multiskb option 020301 --DaveM
* Scaling of results. 020417--sigurdur@linpro.no
+ * 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 impact of around 1%,
+ * as far as I can tell.
+ * --Ben Greear <greearb@candelatech.com>
+ *
+ * Renamed multiskb to clone_skb and cleaned up sending core for two distinct
+ * skb modes. A clone_skb=0 mode for Ben "ranges" work and a clone_skb != 0
+ * as a "fastpath" with a configurable number of clones after alloc's.
+ *
+ * clone_skb=0 means all packets are allocated this also means ranges time
+ * stamps etc can be used. clone_skb=100 means 1 malloc is followed by 100
+ * clones.
+ *
+ * Also moved to /proc/net/pktgen/
+ * --ro
*
* See Documentation/networking/pktgen.txt for how to use this.
*/
@@ -41,6 +67,7 @@
#include <asm/bitops.h>
#include <asm/io.h>
#include <asm/dma.h>
+#include <asm/uaccess.h>
#include <linux/in.h>
#include <linux/ip.h>
@@ -56,73 +83,207 @@
#define cycles() ((u32)get_cycles())
+
+#define VERSION "pktgen version 1.2"
static char version[] __initdata =
- "pktgen.c: v1.1 020418: Packet Generator for packet performance testing.\n";
+ "pktgen.c: v1.2: Packet Generator for packet performance testing.\n";
+
+/* Used to help with determining the pkts on receive */
+
+#define PKTGEN_MAGIC 0xbe9be955
+
+
+/* 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;
+
+#define F_IPSRC_RND (1<<0) /* IP-Src Random */
+#define F_IPDST_RND (1<<1) /* IP-Dst Random */
+#define F_UDPSRC_RND (1<<2) /* UDP-Src Random */
+#define F_UDPDST_RND (1<<3) /* UDP-Dst Random */
+#define F_MACSRC_RND (1<<4) /* MAC-Src Random */
+#define F_MACDST_RND (1<<5) /* MAC-Dst Random */
+#define F_SET_SRCMAC (1<<6) /* Specify-Src-Mac
+ (default is to use Interface's MAC Addr) */
+#define F_SET_SRCIP (1<<7) /* Specify-Src-IP
+ (default is to use Interface's IP Addr) */
+
+
+ int pkt_size; /* = ETH_ZLEN; */
+ int nfrags;
+ __u32 ipg; /* Default Interpacket gap in nsec */
+ __u64 count; /* Default No packets to send */
+ __u64 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 clone_skb; /* Use multiple SKBs during packet gen. If this number
+ * is greater than 1, then that many coppies of the same
+ * packet will be sent before a new packet is allocated.
+ * For instance, if you want to send 1024 identical packets
+ * before creating a new packet, set clone_skb to 1024.
+ */
+ int busy;
+ int do_run_run; /* if this changes to false, the test will stop */
+
+ char 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 result[512];
+
+ /* proc file names */
+ char fname[80];
+ char busy_fname[80];
+
+ struct proc_dir_entry *proc_ent;
+ struct proc_dir_entry *busy_proc_ent;
+};
-/* 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. */
+struct pktgen_hdr {
+ __u32 pgh_magic;
+ __u32 seq_num;
+ struct timeval timestamp;
+};
+static int cpu_speed;
static int debug;
-static int forced_stop;
-static int pg_cpu_speed;
-static int pg_busy;
-static __u8 hh[14] = {
+/* Module parameters, defaults. */
+static int count_d = 100000;
+static int ipg_d = 0;
+static int clone_skb_d = 0;
- /* Overrun by /proc config */
- 0x00, 0x80, 0xC8, 0x79, 0xB3, 0xCB,
+#define MAX_PKTGEN 8
+static struct pktgen_info pginfos[MAX_PKTGEN];
- /* We fill in SRC address later */
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x08, 0x00
-};
-static unsigned char *pg_dstmac = hh;
-static char pg_result[512];
+/** 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);
+}
+
+#define PG_PROC_DIR "pktgen"
+static struct proc_dir_entry *proc_dir = 0;
-static struct net_device *pg_setup_inject(u32 *saddrp)
+static struct net_device *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->outdev);
if (!odev) {
- sprintf(pg_result, "No such netdevice: \"%s\"", pg_outdev);
+ sprintf(info->result, "No such netdevice: \"%s\"", info->outdev);
goto out_unlock;
}
if (odev->type != ARPHRD_ETHER) {
- sprintf(pg_result, "Not ethernet device: \"%s\"", pg_outdev);
+ sprintf(info->result, "Not ethernet device: \"%s\"", info->outdev);
goto out_unlock;
}
if (!netif_running(odev)) {
- sprintf(pg_result, "Device is down: \"%s\"", pg_outdev);
+ sprintf(info->result, "Device is down: \"%s\"", info->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 & F_SET_SRCMAC)) {
+ 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:
@@ -130,9 +291,7 @@
return NULL;
}
-static u32 idle_acc_lo, idle_acc_hi;
-
-static void nanospin(int pg_ipg)
+static void nanospin(int ipg, struct pktgen_info* info)
{
u32 idle_start, idle;
@@ -141,12 +300,10 @@
for (;;) {
barrier();
idle = cycles() - idle_start;
- if (idle * 1000 >= pg_ipg * pg_cpu_speed)
+ if (idle * 1000 >= ipg * cpu_speed)
break;
}
- idle_acc_lo += idle;
- if (idle_acc_lo < idle)
- idle_acc_hi++;
+ info->idle_acc += idle;
}
static int calc_mhz(void)
@@ -172,22 +329,141 @@
for (i = 0; i < 3; i++) {
int res = calc_mhz();
- if (res > pg_cpu_speed)
- pg_cpu_speed = res;
+ if (res > cpu_speed)
+ cpu_speed = res;
}
}
-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 & F_MACSRC_RND) {
+ 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 & F_MACDST_RND) {
+ 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 & F_UDPSRC_RND) {
+ 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 & F_UDPDST_RND) {
+ 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 & F_IPSRC_RND) {
+ 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 & F_IPDST_RND) {
+ 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->result, "No memory");
return NULL;
}
@@ -198,15 +474,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 */
@@ -215,8 +496,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);
@@ -227,12 +508,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) {
@@ -276,79 +560,126 @@
}
}
+ /* Stamp the time, and sequence number, convert them to network byte order */
+ if (pgh) {
+ pgh->pgh_magic = 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 inject(struct pktgen_info* info)
{
- u32 saddr;
- struct net_device *odev;
- struct sk_buff *skb;
- struct timeval start, stop;
- u32 total, idle;
- u32 pc, lcount;
- char *p = pg_result;
- u32 pkt_rate, data_rate;
- char rate_unit;
+ struct net_device *odev = NULL;
+ struct sk_buff *skb = NULL;
+ __u64 total = 0;
+ __u64 idle = 0;
+ __u64 lcount = 0;
+ int nr_frags = 0;
+ int last_ok = 1; /* Was last skb sent?
+ * Or a failed transmit of some sort? This will keep
+ * sequence numbers in order, for example.
+ */
+ __u64 fp = 0;
+ __u32 fp_tmp = 0;
- odev = pg_setup_inject(&saddr);
+ odev = 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);
+ info->do_run_run = 1; /* Cranke yeself! */
+ info->idle_acc = 0;
+ info->sofar = 0;
+ lcount = info->count;
+
+
+ /* Build our initial pkt and place it as a re-try pkt. */
+ skb = fill_packet(odev, info);
+ if (skb == NULL) goto out_reldev;
+
+ do_gettimeofday(&(info->started_at));
+
+ while(info->do_run_run) {
+
+ /* Set a time-stamp, so build a new pkt each time */
+
+ if (last_ok) {
+ if (++fp_tmp >= info->clone_skb ) {
+ kfree_skb(skb);
+ skb = fill_packet(odev, info);
+ if (skb == NULL) {
+ break;
+ }
+ fp++;
+ fp_tmp = 0; /* reset counter */
+ }
+ atomic_inc(&skb->users);
+ }
- for(;;) {
+ 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)
- 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 (odev->hard_start_xmit(skb, odev)) {
+ if (net_ratelimit()) {
+ printk(KERN_INFO "Hard xmit error\n");
+ }
+ info->errors++;
+ last_ok = 0;
}
- pc++;
+ else {
+ last_ok = 1;
+ info->sofar++;
+ info->seq_num++;
+ }
}
- skip:
+ else {
+ /* Re-try it next time */
+ last_ok = 0;
+ }
+
+
spin_unlock_bh(&odev->xmit_lock);
- if (pg_ipg)
- nanospin(pg_ipg);
- if (forced_stop)
- goto out_intr;
- if (signal_pending(current))
- goto out_intr;
+ if (info->ipg) {
+ /* Try not to busy-spin if we have larger sleep times.
+ * TODO: Investigate better ways to do this.
+ */
+ if (info->ipg < 10000) { /* 10 usecs or less */
+ nanospin(info->ipg, info);
+ }
+ else if (info->ipg < 10000000) { /* 10ms or less */
+ udelay(info->ipg / 1000);
+ }
+ else {
+ mdelay(info->ipg / 1000000);
+ }
+ }
+
+ if (signal_pending(current)) {
+ 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;
idle_start = cycles();
while (atomic_read(&skb->users) != 1) {
- if (signal_pending(current))
- goto out_intr;
+ if (signal_pending(current)) {
+ break;
+ }
schedule();
}
idle = cycles() - idle_start;
- idle_acc_lo += idle;
- if (idle_acc_lo < idle)
- idle_acc_hi++;
+ info->idle_acc += idle;
}
break;
}
@@ -358,110 +689,160 @@
idle_start = cycles();
do {
- if (signal_pending(current))
- goto out_intr;
- if (!netif_running(odev))
- goto out_intr;
+ if (signal_pending(current)) {
+ info->do_run_run = 0;
+ break;
+ }
+ if (!netif_running(odev)) {
+ info->do_run_run = 0;
+ break;
+ }
if (current->need_resched)
schedule();
else
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;
- if (total == 0) total = 1; /* division by zero protection */
-
- idle = (((idle_acc_hi<<20)/pg_cpu_speed)<<12)+idle_acc_lo/pg_cpu_speed;
+ idle = (__u32)(info->idle_acc)/(__u32)(cpu_speed);
-
- /*
- Rounding errors is around 1% on pkt_rate when total
- is just over 100.000. When total is big (total >=
- 4.295 sec) pc need to be more than 430 to keep
- rounding errors below 1%. Shouldn't be a problem:)
-
- */
-
- if (total < 100000)
- pkt_rate = (pc*1000000)/total;
- else if (total < 0xFFFFFFFF/1000) /* overflow protection: 2^32/1000 */
- pkt_rate = (pc*1000)/(total/1000);
- else if (total < 0xFFFFFFFF/100)
- pkt_rate = (pc*100)/(total/10000);
- else if (total < 0xFFFFFFFF/10)
- pkt_rate = (pc*10)/(total/100000);
- else
- pkt_rate = (pc/(total/1000000));
-
- data_rate = (pkt_rate*pkt_size);
- if (data_rate > 1024*1024 ) { /* 10 MB/s */
- data_rate = data_rate / (1024*1024);
- rate_unit = 'M';
- } else {
- data_rate = data_rate / 1024;
- rate_unit = 'K';
+ {
+ char *p = info->result;
+ __u64 pps = (__u32)(info->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",
+ (unsigned long long) total,
+ (unsigned long long) (total - idle),
+ (unsigned long long) idle,
+ (unsigned long long) info->sofar,
+ skb->len + 4, /* Add 4 to account for the ethernet checksum */
+ nr_frags,
+ (unsigned long long) pps,
+ (unsigned long long) (bps / (u64) 1024 / (u64) 1024),
+ (unsigned long long) bps,
+ (unsigned long long) info->errors
+ );
}
-
- p += sprintf(p, "OK: %u(c%u+d%u) usec, %u (%dbyte,%dfrags) %upps %u%cB/sec",
- total, total-idle, idle,
- pc, skb->len, skb_shinfo(skb)->nr_frags,
- pkt_rate, data_rate, rate_unit
- );
-
-
-out_relskb:
- kfree_skb(skb);
+
out_reldev:
- dev_put(odev);
+ if (odev) {
+ dev_put(odev);
+ odev = NULL;
+ }
+
+ /* TODO: Is this worth printing out (other than for debug?) */
+ printk("fp = %llu\n", (unsigned long long) fp);
return;
-out_intr:
- sprintf(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;
+/* proc/net/pktgen/pg */
-static int proc_pg_busy_read(char *buf , char **start, off_t offset,
+static int proc_busy_read(char *buf , char **start, off_t offset,
int len, int *eof, void *data)
{
char *p;
+ int idx = (int)(long)(data);
+ struct pktgen_info* info = NULL;
+
+ if ((idx < 0) || (idx >= MAX_PKTGEN)) {
+ printk("ERROR: idx: %i is out of range in proc_write\n", idx);
+ return -EINVAL;
+ }
+ info = &(pginfos[idx]);
p = buf;
- p += sprintf(p, "%d\n", pg_busy);
+ p += sprintf(p, "%d\n", info->busy);
*eof = 1;
return p-buf;
}
-static int proc_pg_read(char *buf , char **start, off_t offset,
+static int proc_read(char *buf , char **start, off_t offset,
int len, int *eof, void *data)
{
char *p;
int i;
+ int idx = (int)(long)(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_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, "%s\n", VERSION); /* Help with parsing compatibility */
+ p += sprintf(p, "Params: count %llu pkt_size: %u frags: %d ipg: %u clone_skb: %d odev \"%s\"\n",
+ (unsigned long long) info->count,
+ info->pkt_size, info->nfrags, info->ipg,
+ info->clone_skb, info->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 & F_IPSRC_RND) {
+ p += sprintf(p, "IPSRC_RND ");
+ }
+ if (info->flags & F_IPDST_RND) {
+ p += sprintf(p, "IPDST_RND ");
+ }
+ if (info->flags & F_UDPSRC_RND) {
+ p += sprintf(p, "UDPSRC_RND ");
+ }
+ if (info->flags & F_UDPDST_RND) {
+ p += sprintf(p, "UDPDST_RND ");
+ }
+ if (info->flags & F_MACSRC_RND) {
+ p += sprintf(p, "MACSRC_RND ");
+ }
+ if (info->flags & F_MACDST_RND) {
+ 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",
+ (unsigned long long) info->sofar,
+ (unsigned long long) info->errors,
+ (unsigned long long) sa,
+ (unsigned long long) stopped,
+ (unsigned long long) now,
+ (unsigned long long) 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->result[0])
+ p += sprintf(p, "Result: %s\n", info->result);
else
p += sprintf(p, "Result: Idle\n");
*eof = 1;
@@ -469,12 +850,16 @@
return p - buf;
}
-static int count_trail_chars(const char *buffer, unsigned int maxlen)
+static int count_trail_chars(const char *user_buffer, unsigned int maxlen)
{
int i;
for (i = 0; i < maxlen; i++) {
- switch (buffer[i]) {
+ char c;
+
+ if (get_user(c, &user_buffer[i]))
+ return -EFAULT;
+ switch (c) {
case '\"':
case '\n':
case '\r':
@@ -490,7 +875,7 @@
return i;
}
-static unsigned long num_arg(const char *buffer, unsigned long maxlen,
+static unsigned long num_arg(const char *user_buffer, unsigned long maxlen,
unsigned long *num)
{
int i = 0;
@@ -498,21 +883,29 @@
*num = 0;
for(; i < maxlen; i++) {
- if ((buffer[i] >= '0') && (buffer[i] <= '9')) {
+ char c;
+
+ if (get_user(c, &user_buffer[i]))
+ return -EFAULT;
+ if ((c >= '0') && (c <= '9')) {
*num *= 10;
- *num += buffer[i] -'0';
+ *num += c -'0';
} else
break;
}
return i;
}
-static int strn_len(const char *buffer, unsigned int maxlen)
+static int strn_len(const char *user_buffer, unsigned int maxlen)
{
int i = 0;
for(; i < maxlen; i++) {
- switch (buffer[i]) {
+ char c;
+
+ if (get_user(c, &user_buffer[i]))
+ return -EFAULT;
+ switch (c) {
case '\"':
case '\n':
case '\r':
@@ -520,123 +913,296 @@
case ' ':
goto done_str;
default:
+ break;
};
}
done_str:
return i;
}
-static int proc_pg_write(struct file *file, const char *buffer,
+static int proc_write(struct file *file, const char *user_buffer,
unsigned long count, void *data)
{
int i = 0, max, len;
char name[16], valstr[32];
unsigned long value = 0;
-
+ int idx = (int)(long)(data);
+ struct pktgen_info* info = NULL;
+ char* result = NULL;
+ int tmp;
+
+ if ((idx < 0) || (idx >= MAX_PKTGEN)) {
+ printk("ERROR: idx: %i is out of range in proc_write\n", idx);
+ return -EINVAL;
+ }
+ info = &(pginfos[idx]);
+ result = &(info->result[0]);
+
if (count < 1) {
- sprintf(pg_result, "Wrong command format");
+ sprintf(result, "Wrong command format");
return -EINVAL;
}
max = count - i;
- i += count_trail_chars(&buffer[i], max);
+ tmp = count_trail_chars(&user_buffer[i], max);
+ if (tmp < 0)
+ return tmp;
+ i += tmp;
/* Read variable name */
- len = strn_len(&buffer[i], sizeof(name) - 1);
+ len = strn_len(&user_buffer[i], sizeof(name) - 1);
+ if (len < 0)
+ return len;
memset(name, 0, sizeof(name));
- strncpy(name, &buffer[i], len);
+ copy_from_user(name, &user_buffer[i], len);
i += len;
max = count -i;
- len = count_trail_chars(&buffer[i], max);
+ len = count_trail_chars(&user_buffer[i], max);
+ if (len < 0)
+ return len;
i += len;
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)
- strcpy(pg_result, "Stopping");
+ if (info->do_run_run) {
+ strcpy(result, "Stopping");
+ }
+ else {
+ strcpy(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);
+ len = num_arg(&user_buffer[i], 10, &value);
+ if (len < 0)
+ return len;
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(result, "OK: pkt_size=%u", info->pkt_size);
return count;
}
if (!strcmp(name, "frags")) {
- len = num_arg(&buffer[i], 10, &value);
+ len = num_arg(&user_buffer[i], 10, &value);
+ if (len < 0)
+ return len;
i += len;
- nfrags = value;
- sprintf(pg_result, "OK: frags=%u", nfrags);
+ info->nfrags = value;
+ sprintf(result, "OK: frags=%u", info->nfrags);
return count;
}
if (!strcmp(name, "ipg")) {
- len = num_arg(&buffer[i], 10, &value);
+ len = num_arg(&user_buffer[i], 10, &value);
+ if (len < 0)
+ return len;
+ i += len;
+ info->ipg = value;
+ sprintf(result, "OK: ipg=%u", info->ipg);
+ return count;
+ }
+ if (!strcmp(name, "udp_src_min")) {
+ len = num_arg(&user_buffer[i], 10, &value);
+ if (len < 0)
+ return len;
+ i += len;
+ info->udp_src_min = value;
+ sprintf(result, "OK: udp_src_min=%u", info->udp_src_min);
+ return count;
+ }
+ if (!strcmp(name, "udp_dst_min")) {
+ len = num_arg(&user_buffer[i], 10, &value);
+ if (len < 0)
+ return len;
+ i += len;
+ info->udp_dst_min = value;
+ sprintf(result, "OK: udp_dst_min=%u", info->udp_dst_min);
+ return count;
+ }
+ if (!strcmp(name, "udp_src_max")) {
+ len = num_arg(&user_buffer[i], 10, &value);
+ if (len < 0)
+ return len;
+ i += len;
+ info->udp_src_max = value;
+ sprintf(result, "OK: udp_src_max=%u", info->udp_src_max);
+ return count;
+ }
+ if (!strcmp(name, "udp_dst_max")) {
+ len = num_arg(&user_buffer[i], 10, &value);
+ if (len < 0)
+ return len;
i += len;
- pg_ipg = value;
- sprintf(pg_result, "OK: ipg=%u", pg_ipg);
+ info->udp_dst_max = value;
+ sprintf(result, "OK: udp_dst_max=%u", info->udp_dst_max);
return count;
}
- if (!strcmp(name, "multiskb")) {
- len = num_arg(&buffer[i], 10, &value);
+ if (!strcmp(name, "clone_skb")) {
+ len = num_arg(&user_buffer[i], 10, &value);
+ if (len < 0)
+ return len;
i += len;
- pg_multiskb = (value ? 1 : 0);
- sprintf(pg_result, "OK: multiskb=%d", pg_multiskb);
+ info->clone_skb = value;
+
+ sprintf(result, "OK: clone_skb=%d", info->clone_skb);
return count;
}
if (!strcmp(name, "count")) {
- len = num_arg(&buffer[i], 10, &value);
+ len = num_arg(&user_buffer[i], 10, &value);
+ if (len < 0)
+ return len;
+ i += len;
+ info->count = value;
+ sprintf(result, "OK: count=%llu", (unsigned long long) info->count);
+ return count;
+ }
+ if (!strcmp(name, "src_mac_count")) {
+ len = num_arg(&user_buffer[i], 10, &value);
+ if (len < 0)
+ return len;
+ i += len;
+ info->src_mac_count = value;
+ sprintf(result, "OK: src_mac_count=%d", info->src_mac_count);
+ return count;
+ }
+ if (!strcmp(name, "dst_mac_count")) {
+ len = num_arg(&user_buffer[i], 10, &value);
+ if (len < 0)
+ return len;
i += len;
- if (value != 0) {
- pg_count = value;
- sprintf(pg_result, "OK: count=%u", pg_count);
- } else
- sprintf(pg_result, "ERROR: no point in sending 0 packets. Leaving count=%u", pg_count);
+ info->dst_mac_count = value;
+ sprintf(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(&user_buffer[i], sizeof(info->outdev) - 1);
+ if (len < 0)
+ return len;
+ memset(info->outdev, 0, sizeof(info->outdev));
+ copy_from_user(info->outdev, &user_buffer[i], len);
+ i += len;
+ sprintf(result, "OK: odev=%s", info->outdev);
+ return count;
+ }
+ if (!strcmp(name, "flag")) {
+ char f[32];
+ memset(f, 0, 32);
+ len = strn_len(&user_buffer[i], sizeof(f) - 1);
+ if (len < 0)
+ return len;
+ copy_from_user(f, &user_buffer[i], len);
+ i += len;
+ if (strcmp(f, "IPSRC_RND") == 0) {
+ info->flags |= F_IPSRC_RND;
+ }
+ else if (strcmp(f, "!IPSRC_RND") == 0) {
+ info->flags &= ~F_IPSRC_RND;
+ }
+ else if (strcmp(f, "IPDST_RND") == 0) {
+ info->flags |= F_IPDST_RND;
+ }
+ else if (strcmp(f, "!IPDST_RND") == 0) {
+ info->flags &= ~F_IPDST_RND;
+ }
+ else if (strcmp(f, "UDPSRC_RND") == 0) {
+ info->flags |= F_UDPSRC_RND;
+ }
+ else if (strcmp(f, "!UDPSRC_RND") == 0) {
+ info->flags &= ~F_UDPSRC_RND;
+ }
+ else if (strcmp(f, "UDPDST_RND") == 0) {
+ info->flags |= F_UDPDST_RND;
+ }
+ else if (strcmp(f, "!UDPDST_RND") == 0) {
+ info->flags &= ~F_UDPDST_RND;
+ }
+ else if (strcmp(f, "MACSRC_RND") == 0) {
+ info->flags |= F_MACSRC_RND;
+ }
+ else if (strcmp(f, "!MACSRC_RND") == 0) {
+ info->flags &= ~F_MACSRC_RND;
+ }
+ else if (strcmp(f, "MACDST_RND") == 0) {
+ info->flags |= F_MACDST_RND;
+ }
+ else if (strcmp(f, "!MACDST_RND") == 0) {
+ info->flags &= ~F_MACDST_RND;
+ }
+ else {
+ sprintf(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(result, "OK: flags=0x%x", info->flags);
+ return count;
+ }
+ if (!strcmp(name, "dst_min") || !strcmp(name, "dst")) {
+ len = strn_len(&user_buffer[i], sizeof(info->dst_min) - 1);
+ if (len < 0)
+ return len;
+ memset(info->dst_min, 0, sizeof(info->dst_min));
+ copy_from_user(info->dst_min, &user_buffer[i], len);
+ if(debug)
+ printk("pg: dst_min set to: %s\n", info->dst_min);
i += len;
- sprintf(pg_result, "OK: odev=%s", pg_outdev);
+ sprintf(result, "OK: dst_min=%s", info->dst_min);
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_max")) {
+ len = strn_len(&user_buffer[i], sizeof(info->dst_max) - 1);
+ if (len < 0)
+ return len;
+ memset(info->dst_max, 0, sizeof(info->dst_max));
+ copy_from_user(info->dst_max, &user_buffer[i], len);
if(debug)
- printk("pg: dst set to: %s\n", pg_dst);
+ printk("pg: dst_max set to: %s\n", info->dst_max);
i += len;
- sprintf(pg_result, "OK: dst=%s", pg_dst);
+ sprintf(result, "OK: dst_max=%s", info->dst_max);
+ return count;
+ }
+ if (!strcmp(name, "src_min")) {
+ len = strn_len(&user_buffer[i], sizeof(info->src_min) - 1);
+ if (len < 0)
+ return len;
+ memset(info->src_min, 0, sizeof(info->src_min));
+ copy_from_user(info->src_min, &user_buffer[i], len);
+ if(debug)
+ printk("pg: src_min set to: %s\n", info->src_min);
+ i += len;
+ sprintf(result, "OK: src_min=%s", info->src_min);
+ return count;
+ }
+ if (!strcmp(name, "src_max")) {
+ len = strn_len(&user_buffer[i], sizeof(info->src_max) - 1);
+ if (len < 0)
+ return len;
+ memset(info->src_max, 0, sizeof(info->src_max));
+ copy_from_user(info->src_max, &user_buffer[i], len);
+ if(debug)
+ printk("pg: src_max set to: %s\n", info->src_max);
+ i += len;
+ sprintf(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);
+ len = strn_len(&user_buffer[i], sizeof(valstr) - 1);
+ if (len < 0)
+ return len;
memset(valstr, 0, sizeof(valstr));
- strncpy(valstr, &buffer[i], len);
+ copy_from_user(valstr, &user_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';
@@ -654,66 +1220,171 @@
*m = 0;
}
}
- sprintf(pg_result, "OK: dstmac");
+ sprintf(result, "OK: dstmac");
+ return count;
+ }
+ if (!strcmp(name, "srcmac")) {
+ char *v = valstr;
+ unsigned char *m = info->src_mac;
+
+ len = strn_len(&user_buffer[i], sizeof(valstr) - 1);
+ if (len < 0)
+ return len;
+ memset(valstr, 0, sizeof(valstr));
+ copy_from_user(valstr, &user_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(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->busy) {
+ strcpy(info->result, "Already running...\n");
+ }
+ else {
+ info->busy = 1;
+ strcpy(info->result, "Starting");
+ inject(info);
+ info->busy = 0;
+ }
MOD_DEC_USE_COUNT;
return count;
}
- sprintf(pg_result, "No such parameter \"%s\"", name);
+ sprintf(info->result, "No such parameter \"%s\"", name);
return -EINVAL;
}
-static int __init pg_init(void)
+
+int create_proc_dir(void)
+{
+ int len;
+ /* does proc_dir already exists */
+ len = strlen(PG_PROC_DIR);
+
+ for (proc_dir = proc_net->subdir; proc_dir;
+ proc_dir=proc_dir->next) {
+ if ((proc_dir->namelen == len) &&
+ (! memcmp(proc_dir->name, PG_PROC_DIR, len)))
+ break;
+ }
+ if (!proc_dir)
+ proc_dir = create_proc_entry(PG_PROC_DIR, S_IFDIR, proc_net);
+ if (!proc_dir) return -ENODEV;
+ return 1;
+}
+
+int remove_proc_dir(void)
{
+ remove_proc_entry(PG_PROC_DIR, proc_net);
+ return 1;
+}
+
+static int __init init(void)
+{
+ int i;
printk(version);
cycles_calibrate();
- if (pg_cpu_speed == 0) {
+ if (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;
+ create_proc_dir();
- 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].clone_skb = clone_skb_d;
+ pginfos[i].ipg = ipg_d;
+ pginfos[i].count = count_d;
+ pginfos[i].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/%s/pg%i", PG_PROC_DIR, i);
+ pginfos[i].proc_ent = create_proc_entry(pginfos[i].fname, 0600, 0);
+ if (!pginfos[i].proc_ent) {
+ printk("pktgen: Error: cannot create net/%s/pg procfs entry.\n", PG_PROC_DIR);
+ goto cleanup_mem;
+ }
+ pginfos[i].proc_ent->read_proc = proc_read;
+ pginfos[i].proc_ent->write_proc = proc_write;
+ pginfos[i].proc_ent->data = (void*)(long)(i);
+
+ sprintf(pginfos[i].busy_fname, "net/%s/pg_busy%i", PG_PROC_DIR, i);
+ pginfos[i].busy_proc_ent = create_proc_entry(pginfos[i].busy_fname, 0, 0);
+ if (!pginfos[i].busy_proc_ent) {
+ printk("pktgen: Error: cannot create net/%s/pg_busy procfs entry.\n", PG_PROC_DIR);
+ goto cleanup_mem;
+ }
+ pginfos[i].busy_proc_ent->read_proc = proc_busy_read;
+ pginfos[i].busy_proc_ent->data = (void*)(long)(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)
+
+static void __exit 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);
+ }
+ }
+ remove_proc_dir();
}
-module_init(pg_init);
-module_exit(pg_cleanup);
+module_init(init);
+module_exit(cleanup);
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_cpu_speed, "i");
-MODULE_PARM(pg_multiskb, "i");
+MODULE_PARM(count_d, "i");
+MODULE_PARM(ipg_d, "i");
+MODULE_PARM(cpu_speed, "i");
+MODULE_PARM(clone_skb_d, "i");
+
+
+
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)