* [PATCH 2.5.44] Pktgen for 2.5.44
@ 2002-10-29 20:00 Lucio Maciel
2002-10-31 10:38 ` Robert Olsson
2002-11-02 10:27 ` [PATCH 2.5.44] Pktgen for 2.5.44 David S. Miller
0 siblings, 2 replies; 7+ messages in thread
From: Lucio Maciel @ 2002-10-29 20:00 UTC (permalink / raw)
To: LKML; +Cc: David S. Miller, Robert Olsson
[-- Attachment #1: Type: text/plain, Size: 364 bytes --]
Hello...
I have ported (integrated sounds better i think...) pktgen from
2.4.20-rc1 to 2.5.44...
I only need to change current->need_resched to need_resched() in the
source... works fine for me....
I also correct the documentation changing multiskb to clone_skb
best regards
--
::: Lucio F. Maciel
::: abslucio@terra.com.br
::: icq 93065464
::: Absoluta.net
[-- Attachment #2: pktgen.diff --]
[-- Type: text/x-patch, Size: 44376 bytes --]
diff -Naur -X /root/dontdiff linux-2.5.44-ori/Documentation/networking/pktgen.txt linux-2.5.44/Documentation/networking/pktgen.txt
--- linux-2.5.44-ori/Documentation/networking/pktgen.txt 1969-12-31 21:00:00.000000000 -0300
+++ linux-2.5.44/Documentation/networking/pktgen.txt 2002-10-29 15:28:51.000000000 -0300
@@ -0,0 +1,77 @@
+How to use the Linux packet generator module.
+
+1. Enable CONFIG_NET_PKTGEN to compile and build pktgen.o, install it
+ 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/pktgen/pg* files.
+4. Run in shell: ". ipg"
+5. After this two commands are defined:
+ A. "pg" to start generator and to get results.
+ B. "pgset" to change generator parameters. F.e.
+ pgset "clone_skb 100" sets the number of coppies of the same packet
+ will be sent before a new packet is allocated
+ pgset "clone_skb 0" use multiple SKBs for packet generation
+ 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, 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.
+
+---- cut here
+
+#! /bin/sh
+
+modprobe pktgen
+
+PGDEV=/proc/net/pktgen/pg0
+
+function pgset() {
+ local result
+
+ echo $1 > $PGDEV
+
+ result=`cat $PGDEV | fgrep "Result: OK:"`
+ if [ "$result" = "" ]; then
+ cat $PGDEV | fgrep Result:
+ fi
+}
+
+function pg() {
+ echo inject > $PGDEV
+ cat $PGDEV
+}
+
+pgset "odev eth0"
+pgset "dst 0.0.0.0"
+
+---- cut here
diff -Naur -X /root/dontdiff linux-2.5.44-ori/arch/i386/defconfig linux-2.5.44/arch/i386/defconfig
--- linux-2.5.44-ori/arch/i386/defconfig 2002-10-19 01:02:24.000000000 -0300
+++ linux-2.5.44/arch/i386/defconfig 2002-10-29 15:55:04.000000000 -0300
@@ -443,6 +443,11 @@
# CONFIG_NET_SCHED is not set
#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+
+#
# Network device support
#
CONFIG_NETDEVICES=y
diff -Naur -X /root/dontdiff linux-2.5.44-ori/net/Config.help linux-2.5.44/net/Config.help
--- linux-2.5.44-ori/net/Config.help 2002-10-19 01:01:15.000000000 -0300
+++ linux-2.5.44/net/Config.help 2002-10-29 15:53:00.000000000 -0300
@@ -512,3 +512,18 @@
performance will be written to /proc/net/profile. If you don't know
what it is about, you don't need it: say N.
+CONFIG_NET_PKTGEN
+ This module will inject preconfigured packets, at a configurable
+ rate, out of a given interface. It is used for network interface
+ stress testing and performance analysis. If you don't understand
+ what was just said, you don't need it: say N.
+
+ Documentation on how to use the packet generator can be found
+ at <file:Documentation/networking/pktgen.txt>.
+
+ This code is also available as a module called pktgen.o ( = code
+ which can be inserted in and removed from the running kernel
+ whenever you want). If you want to compile it as a module, say M
+ here and read <file:Documentation/modules.txt>.
+
+
diff -Naur -X /root/dontdiff linux-2.5.44-ori/net/Config.in linux-2.5.44/net/Config.in
--- linux-2.5.44-ori/net/Config.in 2002-10-19 01:01:18.000000000 -0300
+++ linux-2.5.44/net/Config.in 2002-10-29 14:13:11.000000000 -0300
@@ -93,4 +93,10 @@
#bool 'Network code profiler' CONFIG_NET_PROFILE
endmenu
+mainmenu_option next_comment
+comment 'Network testing'
+tristate 'Packet Generator (USE WITH CAUTION)' CONFIG_NET_PKTGEN
+endmenu
+
+
endmenu
diff -Naur -X /root/dontdiff linux-2.5.44-ori/net/core/Makefile linux-2.5.44/net/core/Makefile
--- linux-2.5.44-ori/net/core/Makefile 2002-10-19 01:02:31.000000000 -0300
+++ linux-2.5.44/net/core/Makefile 2002-10-29 14:13:33.000000000 -0300
@@ -17,6 +17,7 @@
obj-$(CONFIG_NETFILTER) += netfilter.o
obj-$(CONFIG_NET_DIVERT) += dv.o
obj-$(CONFIG_NET_PROFILE) += profile.o
+obj-$(CONFIG_NET_PKTGEN) += pktgen.o
obj-$(CONFIG_NET_RADIO) += wireless.o
# Ugly. I wish all wireless drivers were moved in drivers/net/wireless
obj-$(CONFIG_NET_PCMCIA_RADIO) += wireless.o
diff -Naur -X /root/dontdiff linux-2.5.44-ori/net/core/pktgen.c linux-2.5.44/net/core/pktgen.c
--- linux-2.5.44-ori/net/core/pktgen.c 1969-12-31 21:00:00.000000000 -0300
+++ linux-2.5.44/net/core/pktgen.c 2002-10-29 15:50:23.000000000 -0300
@@ -0,0 +1,1388 @@
+/* -*-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>
+ * Uppsala University, Sweden
+ *
+ * A tool for loading the network with preconfigurated packets.
+ * The tool is implemented as a linux module. Parameters are output
+ * device, IPG (interpacket gap), number of packets, and whether
+ * to use multiple SKBs or just the same one.
+ * pktgen uses the installed interface's output routine.
+ *
+ * Additional hacking by:
+ *
+ * Jens.Laas@data.slu.se
+ * Improved by ANK. 010120.
+ * Improved by ANK even more. 010212.
+ * MAC address typo fixed. 010417 --ro
+ * 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>
+ * Integrated to 2.5.x 021029 --Lucio Maciel (luciomaciel@zipmail.com.br)
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/inet.h>
+#include <asm/byteorder.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/uaccess.h>
+
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/udp.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/inetdevice.h>
+#include <linux/rtnetlink.h>
+#include <linux/proc_fs.h>
+#include <linux/if_arp.h>
+#include <net/checksum.h>
+#include <asm/timex.h>
+
+#define cycles() ((u32)get_cycles())
+
+
+#define VERSION "pktgen version 1.2"
+static char version[] __initdata =
+ "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;
+};
+
+struct pktgen_hdr {
+ __u32 pgh_magic;
+ __u32 seq_num;
+ struct timeval timestamp;
+};
+
+static int cpu_speed;
+static int debug;
+
+/* Module parameters, defaults. */
+static int count_d = 100000;
+static int ipg_d = 0;
+static int clone_skb_d = 0;
+
+
+#define MAX_PKTGEN 8
+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);
+}
+
+#define PG_PROC_DIR "pktgen"
+static struct proc_dir_entry *proc_dir = 0;
+
+static struct net_device *setup_inject(struct pktgen_info* info)
+{
+ struct net_device *odev;
+
+ rtnl_lock();
+ odev = __dev_get_by_name(info->outdev);
+ if (!odev) {
+ sprintf(info->result, "No such netdevice: \"%s\"", info->outdev);
+ goto out_unlock;
+ }
+
+ if (odev->type != ARPHRD_ETHER) {
+ sprintf(info->result, "Not ethernet device: \"%s\"", info->outdev);
+ goto out_unlock;
+ }
+
+ if (!netif_running(odev)) {
+ sprintf(info->result, "Device is down: \"%s\"", info->outdev);
+ goto out_unlock;
+ }
+
+ /* 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();
+
+ return odev;
+
+out_unlock:
+ rtnl_unlock();
+ return NULL;
+}
+
+static void nanospin(int ipg, struct pktgen_info* info)
+{
+ u32 idle_start, idle;
+
+ idle_start = cycles();
+
+ for (;;) {
+ barrier();
+ idle = cycles() - idle_start;
+ if (idle * 1000 >= ipg * cpu_speed)
+ break;
+ }
+ info->idle_acc += idle;
+}
+
+static int calc_mhz(void)
+{
+ struct timeval start, stop;
+ u32 start_s, elapsed;
+
+ do_gettimeofday(&start);
+ start_s = cycles();
+ do {
+ barrier();
+ elapsed = cycles() - start_s;
+ if (elapsed == 0)
+ return 0;
+ } while (elapsed < 1000 * 50000);
+ do_gettimeofday(&stop);
+ return elapsed/(stop.tv_usec-start.tv_usec+1000000*(stop.tv_sec-start.tv_sec));
+}
+
+static void cycles_calibrate(void)
+{
+ int i;
+
+ for (i = 0; i < 3; i++) {
+ int res = calc_mhz();
+ if (res > cpu_speed)
+ cpu_speed = res;
+ }
+}
+
+
+/* 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 = NULL;
+ __u8 *eth;
+ struct udphdr *udph;
+ int datalen, iplen;
+ struct iphdr *iph;
+ struct pktgen_hdr *pgh = NULL;
+
+ skb = alloc_skb(info->pkt_size + 64 + 16, GFP_ATOMIC);
+ if (!skb) {
+ sprintf(info->result, "No memory");
+ return NULL;
+ }
+
+ skb_reserve(skb, 16);
+
+ /* Reserve for ethernet and IP header */
+ eth = (__u8 *) skb_push(skb, 14);
+ iph = (struct iphdr *)skb_put(skb, sizeof(struct iphdr));
+ udph = (struct udphdr *)skb_put(skb, sizeof(struct udphdr));
+
+ /* 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 */
+
+ iph->ihl = 5;
+ iph->version = 4;
+ iph->ttl = 3;
+ iph->tos = 0;
+ iph->protocol = IPPROTO_UDP; /* UDP */
+ iph->saddr = info->cur_saddr;
+ iph->daddr = info->cur_daddr;
+ iph->frag_off = 0;
+ iplen = 20 + 8 + datalen;
+ iph->tot_len = htons(iplen);
+ iph->check = 0;
+ iph->check = ip_fast_csum((void *) iph, iph->ihl);
+ skb->protocol = __constant_htons(ETH_P_IP);
+ skb->mac.raw = ((u8 *)iph) - 14;
+ skb->dev = odev;
+ skb->pkt_type = PACKET_HOST;
+
+ if (info->nfrags <= 0) {
+ pgh = (struct pktgen_hdr *)skb_put(skb, datalen);
+ } else {
+ 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) {
+ skb_put(skb, datalen-frags*PAGE_SIZE);
+ datalen = frags*PAGE_SIZE;
+ }
+
+ i = 0;
+ while (datalen > 0) {
+ struct page *page = alloc_pages(GFP_KERNEL, 0);
+ skb_shinfo(skb)->frags[i].page = page;
+ skb_shinfo(skb)->frags[i].page_offset = 0;
+ skb_shinfo(skb)->frags[i].size =
+ (datalen < PAGE_SIZE ? datalen : PAGE_SIZE);
+ datalen -= skb_shinfo(skb)->frags[i].size;
+ skb->len += skb_shinfo(skb)->frags[i].size;
+ skb->data_len += skb_shinfo(skb)->frags[i].size;
+ i++;
+ skb_shinfo(skb)->nr_frags = i;
+ }
+
+ while (i < frags) {
+ int rem;
+
+ if (i == 0)
+ break;
+
+ rem = skb_shinfo(skb)->frags[i - 1].size / 2;
+ if (rem == 0)
+ break;
+
+ skb_shinfo(skb)->frags[i - 1].size -= rem;
+
+ skb_shinfo(skb)->frags[i] = skb_shinfo(skb)->frags[i - 1];
+ get_page(skb_shinfo(skb)->frags[i].page);
+ skb_shinfo(skb)->frags[i].page = skb_shinfo(skb)->frags[i - 1].page;
+ skb_shinfo(skb)->frags[i].page_offset += skb_shinfo(skb)->frags[i - 1].size;
+ skb_shinfo(skb)->frags[i].size = rem;
+ i++;
+ skb_shinfo(skb)->nr_frags = i;
+ }
+ }
+
+ /* 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 inject(struct pktgen_info* info)
+{
+ 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 = setup_inject(info);
+ if (!odev)
+ return;
+
+ 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);
+ }
+
+ nr_frags = skb_shinfo(skb)->nr_frags;
+
+ spin_lock_bh(&odev->xmit_lock);
+ if (!netif_queue_stopped(odev)) {
+
+ if (odev->hard_start_xmit(skb, odev)) {
+ if (net_ratelimit()) {
+ printk(KERN_INFO "Hard xmit error\n");
+ }
+ info->errors++;
+ last_ok = 0;
+ }
+ else {
+ last_ok = 1;
+ info->sofar++;
+ info->seq_num++;
+ }
+ }
+ else {
+ /* Re-try it next time */
+ last_ok = 0;
+ }
+
+
+ spin_unlock_bh(&odev->xmit_lock);
+
+ 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 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)) {
+ break;
+ }
+ schedule();
+ }
+ idle = cycles() - idle_start;
+ info->idle_acc += idle;
+ }
+ break;
+ }
+
+ if (netif_queue_stopped(odev) || need_resched()) {
+ u32 idle_start, idle;
+
+ idle_start = cycles();
+ do {
+ if (signal_pending(current)) {
+ info->do_run_run = 0;
+ break;
+ }
+ if (!netif_running(odev)) {
+ info->do_run_run = 0;
+ break;
+ }
+ if (need_resched())
+ schedule();
+ else
+ do_softirq();
+ } while (netif_queue_stopped(odev));
+ idle = cycles() - idle_start;
+ info->idle_acc += idle;
+ }
+ }/* while we should be running */
+
+ do_gettimeofday(&(info->stopped_at));
+
+ total = (info->stopped_at.tv_sec - info->started_at.tv_sec) * 1000000 +
+ info->stopped_at.tv_usec - info->started_at.tv_usec;
+
+ idle = (__u32)(info->idle_acc)/(__u32)(cpu_speed);
+
+ {
+ 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
+ );
+ }
+
+out_reldev:
+ 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;
+
+}
+
+/* proc/net/pktgen/pg */
+
+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", info->busy);
+ *eof = 1;
+
+ return p-buf;
+}
+
+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, "%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;
+
+ return p - buf;
+}
+
+static int count_trail_chars(const char *user_buffer, unsigned int maxlen)
+{
+ int i;
+
+ for (i = 0; i < maxlen; i++) {
+ char c;
+
+ if (get_user(c, &user_buffer[i]))
+ return -EFAULT;
+ switch (c) {
+ case '\"':
+ case '\n':
+ case '\r':
+ case '\t':
+ case ' ':
+ case '=':
+ break;
+ default:
+ goto done;
+ };
+ }
+done:
+ return i;
+}
+
+static unsigned long num_arg(const char *user_buffer, unsigned long maxlen,
+ unsigned long *num)
+{
+ int i = 0;
+
+ *num = 0;
+
+ for(; i < maxlen; i++) {
+ char c;
+
+ if (get_user(c, &user_buffer[i]))
+ return -EFAULT;
+ if ((c >= '0') && (c <= '9')) {
+ *num *= 10;
+ *num += c -'0';
+ } else
+ break;
+ }
+ return i;
+}
+
+static int strn_len(const char *user_buffer, unsigned int maxlen)
+{
+ int i = 0;
+
+ for(; i < maxlen; i++) {
+ char c;
+
+ if (get_user(c, &user_buffer[i]))
+ return -EFAULT;
+ switch (c) {
+ case '\"':
+ case '\n':
+ case '\r':
+ case '\t':
+ case ' ':
+ goto done_str;
+ default:
+ break;
+ };
+ }
+done_str:
+ return i;
+}
+
+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(result, "Wrong command format");
+ return -EINVAL;
+ }
+
+ max = count - i;
+ tmp = count_trail_chars(&user_buffer[i], max);
+ if (tmp < 0)
+ return tmp;
+ i += tmp;
+
+ /* Read variable name */
+
+ len = strn_len(&user_buffer[i], sizeof(name) - 1);
+ if (len < 0)
+ return len;
+ memset(name, 0, sizeof(name));
+ copy_from_user(name, &user_buffer[i], len);
+ i += len;
+
+ max = count -i;
+ len = count_trail_chars(&user_buffer[i], max);
+ if (len < 0)
+ return len;
+ i += len;
+
+ if (debug)
+ printk("pg: %s,%lu\n", name, count);
+
+ if (!strcmp(name, "stop")) {
+ if (info->do_run_run) {
+ strcpy(result, "Stopping");
+ }
+ else {
+ strcpy(result, "Already stopped...\n");
+ }
+ info->do_run_run = 0;
+ return count;
+ }
+
+ if (!strcmp(name, "pkt_size")) {
+ len = num_arg(&user_buffer[i], 10, &value);
+ if (len < 0)
+ return len;
+ i += len;
+ if (value < 14+20+8)
+ value = 14+20+8;
+ info->pkt_size = value;
+ sprintf(result, "OK: pkt_size=%u", info->pkt_size);
+ return count;
+ }
+ if (!strcmp(name, "frags")) {
+ len = num_arg(&user_buffer[i], 10, &value);
+ if (len < 0)
+ return len;
+ i += len;
+ info->nfrags = value;
+ sprintf(result, "OK: frags=%u", info->nfrags);
+ return count;
+ }
+ if (!strcmp(name, "ipg")) {
+ 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;
+ info->udp_dst_max = value;
+ sprintf(result, "OK: udp_dst_max=%u", info->udp_dst_max);
+ return count;
+ }
+ if (!strcmp(name, "clone_skb")) {
+ len = num_arg(&user_buffer[i], 10, &value);
+ if (len < 0)
+ return len;
+ i += len;
+ info->clone_skb = value;
+
+ sprintf(result, "OK: clone_skb=%d", info->clone_skb);
+ return count;
+ }
+ if (!strcmp(name, "count")) {
+ 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;
+ 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(&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(result, "OK: dst_min=%s", info->dst_min);
+ return count;
+ }
+ 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_max set to: %s\n", info->dst_max);
+ i += len;
+ 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 = info->dst_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->dst_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: 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;
+ 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(info->result, "No such parameter \"%s\"", name);
+ return -EINVAL;
+}
+
+
+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 (cpu_speed == 0) {
+ printk("pktgen: Error: your machine does not have working cycle counter.\n");
+ return -EINVAL;
+ }
+
+ create_proc_dir();
+
+ 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 cleanup(void)
+{
+ 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(init);
+module_exit(cleanup);
+
+MODULE_AUTHOR("Robert Olsson <robert.olsson@its.uu.se");
+MODULE_DESCRIPTION("Packet Generator tool");
+MODULE_LICENSE("GPL");
+MODULE_PARM(count_d, "i");
+MODULE_PARM(ipg_d, "i");
+MODULE_PARM(cpu_speed, "i");
+MODULE_PARM(clone_skb_d, "i");
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH 2.5.44] Pktgen for 2.5.44
2002-10-29 20:00 [PATCH 2.5.44] Pktgen for 2.5.44 Lucio Maciel
@ 2002-10-31 10:38 ` Robert Olsson
2002-10-31 10:41 ` Kernel bug in 2.4.7-10smp Adriano Galano
2002-11-02 10:27 ` [PATCH 2.5.44] Pktgen for 2.5.44 David S. Miller
1 sibling, 1 reply; 7+ messages in thread
From: Robert Olsson @ 2002-10-31 10:38 UTC (permalink / raw)
To: Lucio Maciel; +Cc: LKML, David S. Miller, Robert Olsson
> Hello...
> I have ported (integrated sounds better i think...) pktgen from
> 2.4.20-rc1 to 2.5.44...
> I only need to change current->need_resched to need_resched() in the
> source... works fine for me....
> I also correct the documentation changing multiskb to clone_skb
> best regards
Thanks!
There is also work going on with a "threaded" version with one process per CPU
a la ksoftirqd. And to each thread/CPU you can add single or multiple devices.
But this work needs some more time. So your patch should be fine now.
Cheers.
--ro
^ permalink raw reply [flat|nested] 7+ messages in thread
* Kernel bug in 2.4.7-10smp...
2002-10-31 10:38 ` Robert Olsson
@ 2002-10-31 10:41 ` Adriano Galano
2002-10-31 11:54 ` Alan Cox
0 siblings, 1 reply; 7+ messages in thread
From: Adriano Galano @ 2002-10-31 10:41 UTC (permalink / raw)
To: 'LKML'
Hi:
I'm using RH Linux 7.2 (kernel 2.4.7-10smp) in one Compaq Proliant ML570
with 4 Xeon procesors at 900MHz and one Compaq Smart Array 5300 Controller
with 6x73 GB SCSI disk with ext3 filesystem.
It was working OK, but I have one trouble, description below, and the
computer it's stopped. Could someone help me? How could I fix it?
Oct 20 04:13:24 virtual3 kernel: Unable to handle kernel paging request
at virtual address a5e7ba0b
Oct 20 04:13:24 virtual3 kernel: printing eip:
Oct 20 04:13:24 virtual3 kernel: c0144d00
Oct 20 04:13:24 virtual3 kernel: *pde = 00000000
Oct 20 04:13:24 virtual3 kernel: Oops: 0000
Oct 20 04:13:24 virtual3 kernel: CPU: 0
Oct 20 04:13:24 virtual3 kernel: EIP: 0010:[cdfind+16/48]
Oct 20 04:13:24 virtual3 kernel: EIP: 0010:[]
Oct 20 04:13:24 virtual3 kernel: EFLAGS: 00010287
Oct 20 04:13:24 virtual3 kernel: eax: a5e7b9ff ebx: f5c898c0 ecx:
00004402 edx: c0313630
Oct 20 04:13:24 virtual3 kernel: esi: f5c898c0 edi: 00004402 ebp:
c0313630 esp: d80dbe04
Oct 20 04:13:24 virtual3 kernel: ds: 0018 es: 0018 ss: 0018
Oct 20 04:13:24 virtual3 kernel: Process updatedb (pid: 30973,
stackpage=d80db000)
Oct 20 04:13:24 virtual3 kernel: Stack: c0144d60 00004402 c0313630
000000b0 f5c898c0 f5c898c0 00004402 f6a7dc00
Oct 20 04:13:24 virtual3 kernel: c013d079 00004402 00000000 f88573a3
f5c898c0 00002180 00004402 f67a1de0
Oct 20 04:13:24 virtual3 kernel: f679e354 00000282 00000000 c09aec60
d934ad80 00000002 c0152fbf 00000000
Oct 20 04:13:24 virtual3 kernel: Call Trace: [cdget+64/224]
[init_special_inode+57/192]
[eepro100:__insmod_eepro100_O/lib/modules/2.4.7-10smp/kernel/drivers/+-62166
1/96]
[get_new_inode+79/384] [get_new_inode+227/384]
Oct 20 04:13:24 virtual3 kernel: Call Trace: [] [] [] [] []
Oct 20 04:13:24 virtual3 kernel: [iget4+217/240]
[eepro100:__insmod_eepro100_O/lib/modules/2.4.7-10smp/kernel/drivers/+-61714
4/96]
[real_lookup+115/272] [path_walk+1646/2288] [__user_walk+58/96]
[sys_lstat64+19/112]
Oct 20 04:13:24 virtual3 kernel: [] [] [] [] [] []
Oct 20 04:13:24 virtual3 kernel: [error_code+56/64] [system_call+51/56]
Oct 20 04:13:24 virtual3 kernel: [] []
Oct 20 04:13:24 virtual3 kernel:
Oct 20 04:13:24 virtual3 kernel: Code: 66 39 48 0c 75 0a f0 ff 40 08 c3
90 8d 74 26 00 8b 00 39 d0
Oct 20 15:21:11 virtual3 kernel: <5>ENOMEM in
journal_get_undo_access_Rsmp_b86db3be, retrying.
Oct 20 15:58:12 virtual3 kernel: ENOMEM in
journal_get_undo_access_Rsmp_b86db3be, retrying.
Oct 20 15:59:33 virtual3 kernel: ENOMEM in do_get_write_access,
retrying.
Oct 20 16:09:35 virtual3 kernel: ENOMEM in
journal_get_undo_access_Rsmp_b86db3be, retrying.
Oct 20 17:33:15 virtual3 kernel: ENOMEM in
journal_get_undo_access_Rsmp_b86db3be, retrying.
Oct 20 17:59:53 virtual3 kernel: ENOMEM in
journal_get_undo_access_Rsmp_b86db3be, retrying.
Oct 20 18:28:11 virtual3 kernel: ENOMEM in do_get_write_access,
retrying.
Oct 20 19:02:55 virtual3 kernel: ENOMEM in
journal_get_undo_access_Rsmp_b86db3be, retrying.
Oct 20 20:37:57 virtual3 kernel: ENOMEM in
journal_get_undo_access_Rsmp_b86db3be, retrying.
Best regards,
-Adriano (bryam)
--
Adriano M. Galano Diez
System & Network Engineer
http://www.satec.es
Phone: (+34) 917 089 000
Sourceforge.NET Linux Kernel Foundry Guide http://sf.net/foundry/linuxkernel
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: Kernel bug in 2.4.7-10smp...
2002-10-31 10:41 ` Kernel bug in 2.4.7-10smp Adriano Galano
@ 2002-10-31 11:54 ` Alan Cox
2002-10-31 15:42 ` Adriano Galano
0 siblings, 1 reply; 7+ messages in thread
From: Alan Cox @ 2002-10-31 11:54 UTC (permalink / raw)
To: Adriano Galano; +Cc: 'LKML'
On Thu, 2002-10-31 at 10:41, Adriano Galano wrote:
> Hi:
>
> I'm using RH Linux 7.2 (kernel 2.4.7-10smp) in one Compaq Proliant ML570
> with 4 Xeon procesors at 900MHz and one Compaq Smart Array 5300 Controller
> with 6x73 GB SCSI disk with ext3 filesystem.
>
> It was working OK, but I have one trouble, description below, and the
> computer it's stopped. Could someone help me? How could I fix it?
Well you could try one of the kernel updates that Red Hat put out for
this release.
^ permalink raw reply [flat|nested] 7+ messages in thread
* RE: Kernel bug in 2.4.7-10smp...
2002-10-31 11:54 ` Alan Cox
@ 2002-10-31 15:42 ` Adriano Galano
2002-10-31 16:42 ` Alan Cox
0 siblings, 1 reply; 7+ messages in thread
From: Adriano Galano @ 2002-10-31 15:42 UTC (permalink / raw)
To: 'Alan Cox'; +Cc: 'LKML'
> On Thu, 2002-10-31 at 10:41, Adriano Galano wrote:
> > Hi:
> >
Hi Alan:
> > I'm using RH Linux 7.2 (kernel 2.4.7-10smp) in one Compaq
> Proliant ML570
> > with 4 Xeon procesors at 900MHz and one Compaq Smart Array
> 5300 Controller
> > with 6x73 GB SCSI disk with ext3 filesystem.
> >
> > It was working OK, but I have one trouble, description
> below, and the
> > computer it's stopped. Could someone help me? How could I fix it?
>
> Well you could try one of the kernel updates that Red Hat put out for
> this release.
>
I don't apply the patches for possible incompatibility with Compaq Remote
Insight Manager card, the drivers of this card are for 2.4.7
(http://www.compaq.com/support/files/server/us/download/15084.html). Now I'm
trying to make one upgrade to 2.4.18 recompiling the drivers source... Why
happen this errors in 2.4.7?
Best regards,
-Adriano (bryam)
--
Adriano M. Galano Diez
System & Network Engineer
http://www.satec.es
Phone: (+34) 917 089 000
Sourceforge.NET Linux Kernel Foundry Guide http://sf.net/foundry/linuxkernel
^ permalink raw reply [flat|nested] 7+ messages in thread
* RE: Kernel bug in 2.4.7-10smp...
2002-10-31 15:42 ` Adriano Galano
@ 2002-10-31 16:42 ` Alan Cox
0 siblings, 0 replies; 7+ messages in thread
From: Alan Cox @ 2002-10-31 16:42 UTC (permalink / raw)
To: Adriano Galano; +Cc: 'LKML'
On Thu, 2002-10-31 at 15:42, Adriano Galano wrote:
> I don't apply the patches for possible incompatibility with Compaq Remote
> Insight Manager card, the drivers of this card are for 2.4.7
> (http://www.compaq.com/support/files/server/us/download/15084.html). Now I'm
> trying to make one upgrade to 2.4.18 recompiling the drivers source... Why
> happen this errors in 2.4.7?
2.4.7 had various bugs that got fixed, like any other software. The old
kernel you are running also has security holes fixed which is a very
good reason to upgrade
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 2.5.44] Pktgen for 2.5.44
2002-10-29 20:00 [PATCH 2.5.44] Pktgen for 2.5.44 Lucio Maciel
2002-10-31 10:38 ` Robert Olsson
@ 2002-11-02 10:27 ` David S. Miller
1 sibling, 0 replies; 7+ messages in thread
From: David S. Miller @ 2002-11-02 10:27 UTC (permalink / raw)
To: abslucio; +Cc: linux-kernel, Robert.Olsson
Thanks a lot, I have applied your patch.
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2002-11-02 10:31 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2002-10-29 20:00 [PATCH 2.5.44] Pktgen for 2.5.44 Lucio Maciel
2002-10-31 10:38 ` Robert Olsson
2002-10-31 10:41 ` Kernel bug in 2.4.7-10smp Adriano Galano
2002-10-31 11:54 ` Alan Cox
2002-10-31 15:42 ` Adriano Galano
2002-10-31 16:42 ` Alan Cox
2002-11-02 10:27 ` [PATCH 2.5.44] Pktgen for 2.5.44 David S. Miller
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.