Blame Modules/pg3.c

Packit Service 6f2e62
/* pg3.c: Packet Generator for packet performance testing.
Packit Service 6f2e62
 *
Packit Service 6f2e62
 * Copyright 2001 by Robert Olsson <robert.olsson@its.uu.se>
Packit Service 6f2e62
 *                                 Uppsala University, Sweden
Packit Service 6f2e62
 *
Packit Service 6f2e62
 * This program is free software; you can redistribute it and/or modify
Packit Service 6f2e62
 * it under the terms of the GNU General Public License as published by
Packit Service 6f2e62
 * the Free Software Foundation; either version 2 of the License, or
Packit Service 6f2e62
 * (at your option) any later version.
Packit Service 6f2e62
 *
Packit Service 6f2e62
 *
Packit Service 6f2e62
 *
Packit Service 6f2e62
 */
Packit Service 6f2e62
Packit Service 6f2e62
/*
Packit Service 6f2e62
Packit Service 6f2e62
A tool for loading a network with a preconfigurated packets. The tool is
Packit Service 6f2e62
implemented as a linux module. Parameters as output device IPG interpacket
Packit Service 6f2e62
packet, number of packets can be configured. pg uses already intalled
Packit Service 6f2e62
device driver output routine.
Packit Service 6f2e62
Packit Service 6f2e62
Packit Service 6f2e62
Additional hacking by:
Packit Service 6f2e62
Packit Service 6f2e62
Jens.Laas@data.slu.se
Packit Service 6f2e62
Improved by ANK. 010120.
Packit Service 6f2e62
Improved by ANK even more. 010212.
Packit Service 6f2e62
MAC address typo fixed. 010417 --ro
Packit Service 6f2e62
Packit Service 6f2e62
Packit Service 6f2e62
TODO:
Packit Service 6f2e62
* could release kernel lock yet.
Packit Service 6f2e62
Packit Service 6f2e62
Packit Service 6f2e62
HOWTO:
Packit Service 6f2e62
Packit Service 6f2e62
1. Compile module pg3.o and install it in the place where modprobe may find it.
Packit Service 6f2e62
2. Cut script "ipg" (see below).
Packit Service 6f2e62
3. Edit script to set preferred device and destination IP address.
Packit Service 6f2e62
4. . ipg
Packit Service 6f2e62
5. After this two commands are defined:
Packit Service 6f2e62
   A. "pg" to start generator and to get results.
Packit Service 6f2e62
   B. "pgset" to change generator parameters. F.e.
Packit Service 6f2e62
      pgset "pkt_size 9014"   sets packet size to 9014
Packit Service 6f2e62
      pgset "frags 5"         packet will consist of 5 fragments
Packit Service 6f2e62
      pgset "count 200000"    sets number of packets to send
Packit Service 6f2e62
      pgset "ipg 5000"        sets artificial gap inserted between packets
Packit Service 6f2e62
			      to 5000 nanoseconds
Packit Service 6f2e62
      pgset "dst 10.0.0.1"    sets IP destination address
Packit Service 6f2e62
			      (BEWARE! This generator is very aggressive!)
Packit Service 6f2e62
      pgset "dstmac 00:00:00:00:00:00"    sets MAC destination address
Packit Service 6f2e62
      pgset stop    	      aborts injection
Packit Service 6f2e62
Packit Service 6f2e62
  Also, ^C aborts generator.
Packit Service 6f2e62
Packit Service 6f2e62
---- cut here
Packit Service 6f2e62
Packit Service 6f2e62
#! /bin/sh
Packit Service 6f2e62
Packit Service 6f2e62
modprobe pg3.o
Packit Service 6f2e62
Packit Service 6f2e62
function pgset() {
Packit Service 6f2e62
    local result
Packit Service 6f2e62
Packit Service 6f2e62
    echo $1 > /proc/net/pg
Packit Service 6f2e62
Packit Service 6f2e62
    result=`cat /proc/net/pg | fgrep "Result: OK:"`
Packit Service 6f2e62
    if [ "$result" = "" ]; then
Packit Service 6f2e62
	 cat /proc/net/pg | fgrep Result:
Packit Service 6f2e62
    fi
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
function pg() {
Packit Service 6f2e62
    echo inject > /proc/net/pg
Packit Service 6f2e62
    cat /proc/net/pg
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
pgset "odev eth0"
Packit Service 6f2e62
pgset "dst 0.0.0.0"
Packit Service 6f2e62
Packit Service 6f2e62
---- cut here
Packit Service 6f2e62
*/
Packit Service 6f2e62
Packit Service 6f2e62
#include <linux/module.h>
Packit Service 6f2e62
#include <linux/kernel.h>
Packit Service 6f2e62
#include <linux/sched.h>
Packit Service 6f2e62
#include <linux/types.h>
Packit Service 6f2e62
#include <linux/string.h>
Packit Service 6f2e62
#include <linux/ptrace.h>
Packit Service 6f2e62
#include <linux/errno.h>
Packit Service 6f2e62
#include <linux/ioport.h>
Packit Service 6f2e62
#include <linux/malloc.h>
Packit Service 6f2e62
#include <linux/interrupt.h>
Packit Service 6f2e62
#include <linux/pci.h>
Packit Service 6f2e62
#include <linux/delay.h>
Packit Service 6f2e62
#include <linux/init.h>
Packit Service 6f2e62
#include <linux/inet.h>
Packit Service 6f2e62
#include <asm/byteorder.h>
Packit Service 6f2e62
#include <asm/bitops.h>
Packit Service 6f2e62
#include <asm/io.h>
Packit Service 6f2e62
#include <asm/dma.h>
Packit Service 6f2e62
Packit Service 6f2e62
#include <linux/in.h>
Packit Service 6f2e62
#include <linux/ip.h>
Packit Service 6f2e62
#include <linux/udp.h>
Packit Service 6f2e62
#include <linux/skbuff.h>
Packit Service 6f2e62
#include <linux/netdevice.h>
Packit Service 6f2e62
#include <linux/inetdevice.h>
Packit Service 6f2e62
#include <linux/rtnetlink.h>
Packit Service 6f2e62
#include <linux/proc_fs.h>
Packit Service 6f2e62
#include <linux/if_arp.h>
Packit Service 6f2e62
#include <net/checksum.h>
Packit Service 6f2e62
Packit Service 6f2e62
static char version[] __initdata =
Packit Service 6f2e62
  "pg3.c: v1.0 010812: Packet Generator for packet performance testing.\n";
Packit Service 6f2e62
Packit Service 6f2e62
Packit Service 6f2e62
Packit Service 6f2e62
/* Parameters */
Packit Service 6f2e62
Packit Service 6f2e62
char pg_outdev[32], pg_dst[32];
Packit Service 6f2e62
int pkt_size=ETH_ZLEN;
Packit Service 6f2e62
int nfrags=0;
Packit Service 6f2e62
__u32 pg_count = 100000;  /* Default No packets to send */
Packit Service 6f2e62
__u32 pg_ipg = 0;  /* Default Interpacket gap in nsec */
Packit Service 6f2e62
Packit Service 6f2e62
/* Globar vars */
Packit Service 6f2e62
Packit Service 6f2e62
int debug;
Packit Service 6f2e62
int forced_stop;
Packit Service 6f2e62
int pg_cpu_speed;
Packit Service 6f2e62
int pg_busy;
Packit Service 6f2e62
Packit Service 6f2e62
static __u8 hh[14] = {
Packit Service 6f2e62
    0x00, 0x80, 0xC8, 0x79, 0xB3, 0xCB,
Packit Service 6f2e62
Packit Service 6f2e62
    /* We fill in SRC address later */
Packit Service 6f2e62
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Packit Service 6f2e62
    0x08, 0x00
Packit Service 6f2e62
};
Packit Service 6f2e62
Packit Service 6f2e62
unsigned char *pg_dstmac = hh;
Packit Service 6f2e62
char pg_result[512];
Packit Service 6f2e62
Packit Service 6f2e62
Packit Service 6f2e62
static struct net_device *pg_setup_inject(u32 *saddrp)
Packit Service 6f2e62
{
Packit Service 6f2e62
	int p1, p2;
Packit Service 6f2e62
	struct net_device *odev;
Packit Service 6f2e62
	u32 saddr;
Packit Service 6f2e62
Packit Service 6f2e62
	rtnl_lock();
Packit Service 6f2e62
	odev = __dev_get_by_name(pg_outdev);
Packit Service 6f2e62
	if (!odev) {
Packit Service 6f2e62
		sprintf(pg_result, "No such netdevice: \"%s\"", pg_outdev);
Packit Service 6f2e62
		goto out_unlock;
Packit Service 6f2e62
	}
Packit Service 6f2e62
Packit Service 6f2e62
	if (odev->type != ARPHRD_ETHER) {
Packit Service 6f2e62
		sprintf(pg_result, "Not ethernet device: \"%s\"", pg_outdev);
Packit Service 6f2e62
		goto out_unlock;
Packit Service 6f2e62
	}
Packit Service 6f2e62
Packit Service 6f2e62
	if (!netif_running(odev)) {
Packit Service 6f2e62
		sprintf(pg_result, "Device is down: \"%s\"", pg_outdev);
Packit Service 6f2e62
		goto out_unlock;
Packit Service 6f2e62
	}
Packit Service 6f2e62
Packit Service 6f2e62
	for(p1=6,p2=0; p1 < odev->addr_len+6;p1++)
Packit Service 6f2e62
		hh[p1]=odev->dev_addr[p2++];
Packit Service 6f2e62
Packit Service 6f2e62
	saddr = 0;
Packit Service 6f2e62
	if (odev->ip_ptr) {
Packit Service 6f2e62
		struct in_device *in_dev = odev->ip_ptr;
Packit Service 6f2e62
Packit Service 6f2e62
		if (in_dev->ifa_list)
Packit Service 6f2e62
			saddr = in_dev->ifa_list->ifa_address;
Packit Service 6f2e62
	}
Packit Service 6f2e62
	atomic_inc(&odev->refcnt);
Packit Service 6f2e62
	rtnl_unlock();
Packit Service 6f2e62
Packit Service 6f2e62
	*saddrp = saddr;
Packit Service 6f2e62
	return odev;
Packit Service 6f2e62
Packit Service 6f2e62
out_unlock:
Packit Service 6f2e62
	rtnl_unlock();
Packit Service 6f2e62
	return NULL;
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
Packit Service 6f2e62
u32 idle_acc_lo, idle_acc_hi;
Packit Service 6f2e62
Packit Service 6f2e62
void nanospin(int pg_ipg)
Packit Service 6f2e62
{
Packit Service 6f2e62
	u32 idle_start, idle;
Packit Service 6f2e62
Packit Service 6f2e62
	idle_start = get_cycles();
Packit Service 6f2e62
Packit Service 6f2e62
	for (;;) {
Packit Service 6f2e62
		barrier();
Packit Service 6f2e62
		idle = get_cycles() - idle_start;
Packit Service 6f2e62
		if (idle*1000 >= pg_ipg*pg_cpu_speed)
Packit Service 6f2e62
			break;
Packit Service 6f2e62
	}
Packit Service 6f2e62
	idle_acc_lo += idle;
Packit Service 6f2e62
	if (idle_acc_lo < idle)
Packit Service 6f2e62
		idle_acc_hi++;
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
int calc_mhz(void)
Packit Service 6f2e62
{
Packit Service 6f2e62
	struct timeval start, stop;
Packit Service 6f2e62
	u32 start_s, elapsed;
Packit Service 6f2e62
Packit Service 6f2e62
	do_gettimeofday(&start;;
Packit Service 6f2e62
	start_s = get_cycles();
Packit Service 6f2e62
	do {
Packit Service 6f2e62
		barrier();
Packit Service 6f2e62
		elapsed = get_cycles() - start_s;
Packit Service 6f2e62
		if (elapsed == 0)
Packit Service 6f2e62
			return 0;
Packit Service 6f2e62
	} while (elapsed < 1000*50000);
Packit Service 6f2e62
	do_gettimeofday(&stop);
Packit Service 6f2e62
	return elapsed/(stop.tv_usec-start.tv_usec+1000000*(stop.tv_sec-start.tv_sec));
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
static void cycles_calibrate(void)
Packit Service 6f2e62
{
Packit Service 6f2e62
	int i;
Packit Service 6f2e62
Packit Service 6f2e62
	for (i=0; i<3; i++) {
Packit Service 6f2e62
		int res = calc_mhz();
Packit Service 6f2e62
		if (res > pg_cpu_speed)
Packit Service 6f2e62
			pg_cpu_speed = res;
Packit Service 6f2e62
	}
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
struct sk_buff *
Packit Service 6f2e62
fill_packet(struct net_device *odev, __u32 saddr)
Packit Service 6f2e62
{
Packit Service 6f2e62
	struct sk_buff *skb;
Packit Service 6f2e62
	__u8 *eth;
Packit Service 6f2e62
	struct udphdr *udph;
Packit Service 6f2e62
	int datalen, iplen;
Packit Service 6f2e62
	struct iphdr *iph;
Packit Service 6f2e62
Packit Service 6f2e62
	skb = alloc_skb(pkt_size+64+16, GFP_ATOMIC);
Packit Service 6f2e62
	if (!skb) {
Packit Service 6f2e62
		sprintf(pg_result, "No memory");
Packit Service 6f2e62
		return NULL;
Packit Service 6f2e62
	}
Packit Service 6f2e62
Packit Service 6f2e62
	skb_reserve(skb, 16);
Packit Service 6f2e62
Packit Service 6f2e62
	/*  Reserve for ethernet and IP header  */
Packit Service 6f2e62
	eth = (__u8 *) skb_push(skb, 14);
Packit Service 6f2e62
	iph = (struct iphdr*)skb_put(skb, sizeof( struct iphdr));
Packit Service 6f2e62
	udph = (struct udphdr*)skb_put(skb, sizeof( struct udphdr));
Packit Service 6f2e62
Packit Service 6f2e62
	/*  Copy the ethernet header  */
Packit Service 6f2e62
	memcpy(eth, hh, 14);
Packit Service 6f2e62
Packit Service 6f2e62
	datalen = pkt_size-14-20-8; /* Eth + IPh + UDPh */
Packit Service 6f2e62
	if (datalen < 0)
Packit Service 6f2e62
		datalen = 0;
Packit Service 6f2e62
Packit Service 6f2e62
	udph->source= htons(9);
Packit Service 6f2e62
	udph->dest= htons(9);
Packit Service 6f2e62
	udph->len= htons(datalen+8); /* DATA + udphdr */
Packit Service 6f2e62
	udph->check=0;  /* No checksum */
Packit Service 6f2e62
Packit Service 6f2e62
	iph->ihl=5;
Packit Service 6f2e62
	iph->version=4;
Packit Service 6f2e62
	iph->ttl=3;
Packit Service 6f2e62
	iph->tos=0;
Packit Service 6f2e62
	iph->protocol = IPPROTO_UDP; /* UDP */
Packit Service 6f2e62
	iph->saddr =  saddr;
Packit Service 6f2e62
	iph->daddr =  in_aton(pg_dst);
Packit Service 6f2e62
	iph->frag_off = 0;
Packit Service 6f2e62
	iplen = 20 + 8 + datalen;
Packit Service 6f2e62
	iph->tot_len = htons(iplen);
Packit Service 6f2e62
	iph->check = 0;
Packit Service 6f2e62
	iph->check = ip_fast_csum((void *)iph, iph->ihl);
Packit Service 6f2e62
	skb->protocol = __constant_htons(ETH_P_IP);
Packit Service 6f2e62
	skb->mac.raw = ((u8*)iph) - 14;
Packit Service 6f2e62
	skb->dev = odev;
Packit Service 6f2e62
	skb->pkt_type = PACKET_HOST;
Packit Service 6f2e62
Packit Service 6f2e62
	if (nfrags<=0) {
Packit Service 6f2e62
		skb_put(skb, datalen);
Packit Service 6f2e62
	} else {
Packit Service 6f2e62
		int frags = nfrags;
Packit Service 6f2e62
		int i;
Packit Service 6f2e62
Packit Service 6f2e62
		if (frags > MAX_SKB_FRAGS)
Packit Service 6f2e62
			frags = MAX_SKB_FRAGS;
Packit Service 6f2e62
		if (datalen > frags*PAGE_SIZE) {
Packit Service 6f2e62
			skb_put(skb, datalen-frags*PAGE_SIZE);
Packit Service 6f2e62
			datalen = frags*PAGE_SIZE;
Packit Service 6f2e62
		}
Packit Service 6f2e62
Packit Service 6f2e62
		i = 0;
Packit Service 6f2e62
		while (datalen > 0) {
Packit Service 6f2e62
			struct page *page = alloc_pages(GFP_KERNEL, 0);
Packit Service 6f2e62
			skb_shinfo(skb)->frags[i].page = page;
Packit Service 6f2e62
			skb_shinfo(skb)->frags[i].page_offset = 0;
Packit Service 6f2e62
			skb_shinfo(skb)->frags[i].size = (datalen < PAGE_SIZE ? datalen : PAGE_SIZE);
Packit Service 6f2e62
			datalen -= skb_shinfo(skb)->frags[i].size;
Packit Service 6f2e62
			skb->len += skb_shinfo(skb)->frags[i].size;
Packit Service 6f2e62
			skb->data_len += skb_shinfo(skb)->frags[i].size;
Packit Service 6f2e62
			i++;
Packit Service 6f2e62
			skb_shinfo(skb)->nr_frags = i;
Packit Service 6f2e62
		}
Packit Service 6f2e62
Packit Service 6f2e62
		while (i < frags) {
Packit Service 6f2e62
			int rem;
Packit Service 6f2e62
Packit Service 6f2e62
			if (i == 0)
Packit Service 6f2e62
				break;
Packit Service 6f2e62
Packit Service 6f2e62
			rem = skb_shinfo(skb)->frags[i-1].size/2;
Packit Service 6f2e62
			if (rem == 0)
Packit Service 6f2e62
				break;
Packit Service 6f2e62
Packit Service 6f2e62
			skb_shinfo(skb)->frags[i-1].size -= rem;
Packit Service 6f2e62
Packit Service 6f2e62
			skb_shinfo(skb)->frags[i] = skb_shinfo(skb)->frags[i-1];
Packit Service 6f2e62
			get_page(skb_shinfo(skb)->frags[i].page);
Packit Service 6f2e62
			skb_shinfo(skb)->frags[i].page = skb_shinfo(skb)->frags[i-1].page;
Packit Service 6f2e62
			skb_shinfo(skb)->frags[i].page_offset += skb_shinfo(skb)->frags[i-1].size;
Packit Service 6f2e62
			skb_shinfo(skb)->frags[i].size = rem;
Packit Service 6f2e62
			i++;
Packit Service 6f2e62
			skb_shinfo(skb)->nr_frags = i;
Packit Service 6f2e62
		}
Packit Service 6f2e62
	}
Packit Service 6f2e62
Packit Service 6f2e62
	return skb;
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
Packit Service 6f2e62
static void pg_inject(void)
Packit Service 6f2e62
{
Packit Service 6f2e62
	u32 saddr;
Packit Service 6f2e62
	struct net_device *odev;
Packit Service 6f2e62
	struct sk_buff *skb;
Packit Service 6f2e62
	struct timeval start, stop;
Packit Service 6f2e62
	u32 total, idle;
Packit Service 6f2e62
	int pc, lcount;
Packit Service 6f2e62
Packit Service 6f2e62
	odev = pg_setup_inject(&saddr);
Packit Service 6f2e62
	if (!odev)
Packit Service 6f2e62
		return;
Packit Service 6f2e62
Packit Service 6f2e62
	skb = fill_packet(odev, saddr);
Packit Service 6f2e62
	if (skb == NULL)
Packit Service 6f2e62
		goto out_reldev;
Packit Service 6f2e62
Packit Service 6f2e62
	forced_stop = 0;
Packit Service 6f2e62
	idle_acc_hi = 0;
Packit Service 6f2e62
	idle_acc_lo = 0;
Packit Service 6f2e62
	pc = 0;
Packit Service 6f2e62
	lcount = pg_count;
Packit Service 6f2e62
	do_gettimeofday(&start;;
Packit Service 6f2e62
Packit Service 6f2e62
	for(;;) {
Packit Service 6f2e62
		spin_lock_bh(&odev->xmit_lock);
Packit Service 6f2e62
		atomic_inc(&skb->users);
Packit Service 6f2e62
		if (!netif_queue_stopped(odev)) {
Packit Service 6f2e62
			if (odev->hard_start_xmit(skb, odev)) {
Packit Service 6f2e62
				kfree_skb(skb);
Packit Service 6f2e62
				if (net_ratelimit())
Packit Service 6f2e62
					printk(KERN_INFO "Hard xmit error\n");
Packit Service 6f2e62
			}
Packit Service 6f2e62
			pc++;
Packit Service 6f2e62
		} else {
Packit Service 6f2e62
			kfree_skb(skb);
Packit Service 6f2e62
		}
Packit Service 6f2e62
		spin_unlock_bh(&odev->xmit_lock);
Packit Service 6f2e62
Packit Service 6f2e62
		if (pg_ipg)
Packit Service 6f2e62
			nanospin(pg_ipg);
Packit Service 6f2e62
		if (forced_stop)
Packit Service 6f2e62
			goto out_intr;
Packit Service 6f2e62
		if (signal_pending(current))
Packit Service 6f2e62
			goto out_intr;
Packit Service 6f2e62
Packit Service 6f2e62
		if (--lcount == 0) {
Packit Service 6f2e62
			if (atomic_read(&skb->users) != 1) {
Packit Service 6f2e62
				u32 idle_start, idle;
Packit Service 6f2e62
Packit Service 6f2e62
				idle_start = get_cycles();
Packit Service 6f2e62
				while (atomic_read(&skb->users) != 1) {
Packit Service 6f2e62
					if (signal_pending(current))
Packit Service 6f2e62
						goto out_intr;
Packit Service 6f2e62
					schedule();
Packit Service 6f2e62
				}
Packit Service 6f2e62
				idle = get_cycles() - idle_start;
Packit Service 6f2e62
				idle_acc_lo += idle;
Packit Service 6f2e62
				if (idle_acc_lo < idle)
Packit Service 6f2e62
					idle_acc_hi++;
Packit Service 6f2e62
			}
Packit Service 6f2e62
			break;
Packit Service 6f2e62
		}
Packit Service 6f2e62
Packit Service 6f2e62
		if (netif_queue_stopped(odev) || current->need_resched) {
Packit Service 6f2e62
			u32 idle_start, idle;
Packit Service 6f2e62
Packit Service 6f2e62
			idle_start = get_cycles();
Packit Service 6f2e62
			do {
Packit Service 6f2e62
				if (signal_pending(current))
Packit Service 6f2e62
					goto out_intr;
Packit Service 6f2e62
				if (!netif_running(odev))
Packit Service 6f2e62
					goto out_intr;
Packit Service 6f2e62
				if (current->need_resched)
Packit Service 6f2e62
					schedule();
Packit Service 6f2e62
				else
Packit Service 6f2e62
					do_softirq();
Packit Service 6f2e62
			} while (netif_queue_stopped(odev));
Packit Service 6f2e62
			idle = get_cycles() - idle_start;
Packit Service 6f2e62
			idle_acc_lo += idle;
Packit Service 6f2e62
			if (idle_acc_lo < idle)
Packit Service 6f2e62
				idle_acc_hi++;
Packit Service 6f2e62
		}
Packit Service 6f2e62
	}
Packit Service 6f2e62
Packit Service 6f2e62
	do_gettimeofday(&stop);
Packit Service 6f2e62
Packit Service 6f2e62
	total = (stop.tv_sec - start.tv_sec)*1000000 +
Packit Service 6f2e62
		stop.tv_usec - start.tv_usec;
Packit Service 6f2e62
Packit Service 6f2e62
	idle = (((idle_acc_hi<<20)/pg_cpu_speed)<<12)+idle_acc_lo/pg_cpu_speed;
Packit Service 6f2e62
Packit Service 6f2e62
	if (1) {
Packit Service 6f2e62
		char *p = pg_result;
Packit Service 6f2e62
Packit Service 6f2e62
		p += sprintf(p, "OK: %u(c%u+d%u) usec, %u (%dbyte,%dfrags) %upps %uMB/sec",
Packit Service 6f2e62
			     total, total-idle, idle,
Packit Service 6f2e62
			     pc, skb->len, skb_shinfo(skb)->nr_frags,
Packit Service 6f2e62
			     ((pc*1000)/(total/1000)),
Packit Service 6f2e62
			     (((pc*1000)/(total/1000))*pkt_size)/1024/1024
Packit Service 6f2e62
			     );
Packit Service 6f2e62
	}
Packit Service 6f2e62
Packit Service 6f2e62
out_relskb:
Packit Service 6f2e62
	kfree_skb(skb);
Packit Service 6f2e62
out_reldev:
Packit Service 6f2e62
	dev_put(odev);
Packit Service 6f2e62
	return;
Packit Service 6f2e62
Packit Service 6f2e62
out_intr:
Packit Service 6f2e62
	sprintf(pg_result, "Interrupted");
Packit Service 6f2e62
	goto out_relskb;
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
/* proc/net/pg */
Packit Service 6f2e62
Packit Service 6f2e62
static struct proc_dir_entry *pg_proc_ent = 0;
Packit Service 6f2e62
static struct proc_dir_entry *pg_busy_proc_ent = 0;
Packit Service 6f2e62
Packit Service 6f2e62
int proc_pg_busy_read(char *buf , char **start, off_t offset,
Packit Service 6f2e62
		      int len, int *eof, void *data)
Packit Service 6f2e62
{
Packit Service 6f2e62
	char *p;
Packit Service 6f2e62
Packit Service 6f2e62
	p = buf;
Packit Service 6f2e62
	p += sprintf(p, "%d\n", pg_busy);
Packit Service 6f2e62
	*eof = 1;
Packit Service 6f2e62
Packit Service 6f2e62
	return p-buf;
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
int proc_pg_read(char *buf , char **start, off_t offset,
Packit Service 6f2e62
		 int len, int *eof, void *data)
Packit Service 6f2e62
{
Packit Service 6f2e62
	char *p;
Packit Service 6f2e62
	int i;
Packit Service 6f2e62
Packit Service 6f2e62
	p = buf;
Packit Service 6f2e62
	p += sprintf(p, "Params: count=%u pkt_size=%u frags %d ipg %u odev \"%s\" dst %s dstmac ",
Packit Service 6f2e62
		     pg_count, pkt_size, nfrags, pg_ipg,
Packit Service 6f2e62
		     pg_outdev, pg_dst);
Packit Service 6f2e62
	for(i=0;i<6;i++)
Packit Service 6f2e62
		p += sprintf(p, "%02X%s", pg_dstmac[i], i == 5 ? "\n" : ":");
Packit Service 6f2e62
Packit Service 6f2e62
	if(pg_result[0])
Packit Service 6f2e62
		p += sprintf(p, "Result: %s\n", pg_result);
Packit Service 6f2e62
	else
Packit Service 6f2e62
		p += sprintf(p, "Result: Idle\n");
Packit Service 6f2e62
	*eof = 1;
Packit Service 6f2e62
	return p-buf;
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
int count_trail_chars(const char *buffer, unsigned int maxlen)
Packit Service 6f2e62
{
Packit Service 6f2e62
	int i;
Packit Service 6f2e62
Packit Service 6f2e62
	for(i=0; i
Packit Service 6f2e62
		switch(buffer[i]) {
Packit Service 6f2e62
		case '\"':
Packit Service 6f2e62
		case '\n':
Packit Service 6f2e62
		case '\r':
Packit Service 6f2e62
		case '\t':
Packit Service 6f2e62
		case ' ':
Packit Service 6f2e62
		case '=':
Packit Service 6f2e62
			break;
Packit Service 6f2e62
		default:
Packit Service 6f2e62
			goto done;
Packit Service 6f2e62
		}
Packit Service 6f2e62
	}
Packit Service 6f2e62
done:
Packit Service 6f2e62
	return i;
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
unsigned long num_arg(const char *buffer, unsigned long maxlen,
Packit Service 6f2e62
		      unsigned long *num)
Packit Service 6f2e62
{
Packit Service 6f2e62
	int i=0;
Packit Service 6f2e62
	*num = 0;
Packit Service 6f2e62
Packit Service 6f2e62
	for(; i
Packit Service 6f2e62
		if( (buffer[i] >= '0') && (buffer[i] <= '9')) {
Packit Service 6f2e62
			*num *= 10;
Packit Service 6f2e62
			*num += buffer[i] -'0';
Packit Service 6f2e62
		}
Packit Service 6f2e62
		else
Packit Service 6f2e62
			break;
Packit Service 6f2e62
	}
Packit Service 6f2e62
	return i;
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
int strn_len(const char *buffer, unsigned int maxlen)
Packit Service 6f2e62
{
Packit Service 6f2e62
	int i=0;
Packit Service 6f2e62
Packit Service 6f2e62
	for(; i
Packit Service 6f2e62
		switch(buffer[i]) {
Packit Service 6f2e62
		case '\"':
Packit Service 6f2e62
		case '\n':
Packit Service 6f2e62
		case '\r':
Packit Service 6f2e62
		case '\t':
Packit Service 6f2e62
		case ' ':
Packit Service 6f2e62
			goto done_str;
Packit Service 6f2e62
		default:
Packit Service 6f2e62
		}
Packit Service 6f2e62
done_str:
Packit Service 6f2e62
	return i;
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
int proc_pg_write(struct file *file, const char *buffer,
Packit Service 6f2e62
		     unsigned long count, void *data)
Packit Service 6f2e62
{
Packit Service 6f2e62
	int i=0, max, len;
Packit Service 6f2e62
	char name[16], valstr[32];
Packit Service 6f2e62
	unsigned long value = 0;
Packit Service 6f2e62
Packit Service 6f2e62
	if (count < 1) {
Packit Service 6f2e62
		sprintf(pg_result, "Wrong command format");
Packit Service 6f2e62
		return -EINVAL;
Packit Service 6f2e62
	}
Packit Service 6f2e62
Packit Service 6f2e62
	max = count -i;
Packit Service 6f2e62
	i += count_trail_chars(&buffer[i], max);
Packit Service 6f2e62
Packit Service 6f2e62
	/* Read variable name */
Packit Service 6f2e62
Packit Service 6f2e62
	len = strn_len(&buffer[i], sizeof(name)-1);
Packit Service 6f2e62
	memset(name, 0, sizeof(name));
Packit Service 6f2e62
	strncpy(name, &buffer[i], len);
Packit Service 6f2e62
	i += len;
Packit Service 6f2e62
Packit Service 6f2e62
	max = count -i;
Packit Service 6f2e62
	len = count_trail_chars(&buffer[i], max);
Packit Service 6f2e62
	i += len;
Packit Service 6f2e62
Packit Service 6f2e62
	if (debug)
Packit Service 6f2e62
		printk("pg: %s,%lu\n", name, count);
Packit Service 6f2e62
Packit Service 6f2e62
	/* Only stop is allowed when we are running */
Packit Service 6f2e62
Packit Service 6f2e62
	if(!strcmp(name, "stop")) {
Packit Service 6f2e62
		forced_stop=1;
Packit Service 6f2e62
		if (pg_busy)
Packit Service 6f2e62
			strcpy(pg_result, "Stopping");
Packit Service 6f2e62
		return count;
Packit Service 6f2e62
	}
Packit Service 6f2e62
Packit Service 6f2e62
	if (pg_busy) {
Packit Service 6f2e62
		strcpy(pg_result, "Busy");
Packit Service 6f2e62
		return -EINVAL;
Packit Service 6f2e62
	}
Packit Service 6f2e62
Packit Service 6f2e62
	if(!strcmp(name, "pkt_size")) {
Packit Service 6f2e62
		len = num_arg(&buffer[i], 10, &value);
Packit Service 6f2e62
		i += len;
Packit Service 6f2e62
		if (value < 14+20+8)
Packit Service 6f2e62
			value = 14+20+8;
Packit Service 6f2e62
		pkt_size = value;
Packit Service 6f2e62
		sprintf(pg_result, "OK: pkt_size=%u", pkt_size);
Packit Service 6f2e62
		return count;
Packit Service 6f2e62
	}
Packit Service 6f2e62
	if(!strcmp(name, "frags")) {
Packit Service 6f2e62
		len = num_arg(&buffer[i], 10, &value);
Packit Service 6f2e62
		i += len;
Packit Service 6f2e62
		nfrags = value;
Packit Service 6f2e62
		sprintf(pg_result, "OK: frags=%u", nfrags);
Packit Service 6f2e62
		return count;
Packit Service 6f2e62
	}
Packit Service 6f2e62
	if(!strcmp(name, "ipg")) {
Packit Service 6f2e62
		len = num_arg(&buffer[i], 10, &value);
Packit Service 6f2e62
		i += len;
Packit Service 6f2e62
		pg_ipg = value;
Packit Service 6f2e62
		sprintf(pg_result, "OK: ipg=%u", pg_ipg);
Packit Service 6f2e62
		return count;
Packit Service 6f2e62
	}
Packit Service 6f2e62
	if(!strcmp(name, "count")) {
Packit Service 6f2e62
		len = num_arg(&buffer[i], 10, &value);
Packit Service 6f2e62
		i += len;
Packit Service 6f2e62
		pg_count = value;
Packit Service 6f2e62
		sprintf(pg_result, "OK: count=%u", pg_count);
Packit Service 6f2e62
		return count;
Packit Service 6f2e62
	}
Packit Service 6f2e62
	if(!strcmp(name, "odev")) {
Packit Service 6f2e62
		len = strn_len(&buffer[i], sizeof(pg_outdev)-1);
Packit Service 6f2e62
		memset(pg_outdev, 0, sizeof(pg_outdev));
Packit Service 6f2e62
		strncpy(pg_outdev, &buffer[i], len);
Packit Service 6f2e62
		i += len;
Packit Service 6f2e62
		sprintf(pg_result, "OK: odev=%s", pg_outdev);
Packit Service 6f2e62
		return count;
Packit Service 6f2e62
	}
Packit Service 6f2e62
	if(!strcmp(name, "dst")) {
Packit Service 6f2e62
		len = strn_len(&buffer[i], sizeof(pg_dst)-1);
Packit Service 6f2e62
		memset(pg_dst, 0, sizeof(pg_dst));
Packit Service 6f2e62
		strncpy(pg_dst, &buffer[i], len);
Packit Service 6f2e62
		if(debug)
Packit Service 6f2e62
			printk("pg: dst set to: %s\n", pg_dst);
Packit Service 6f2e62
		i += len;
Packit Service 6f2e62
		sprintf(pg_result, "OK: dst=%s", pg_dst);
Packit Service 6f2e62
		return count;
Packit Service 6f2e62
	}
Packit Service 6f2e62
	if(!strcmp(name, "dstmac")) {
Packit Service 6f2e62
		char *v = valstr;
Packit Service 6f2e62
		unsigned char *m = pg_dstmac;
Packit Service 6f2e62
Packit Service 6f2e62
		len = strn_len(&buffer[i], sizeof(valstr)-1);
Packit Service 6f2e62
		memset(valstr, 0, sizeof(valstr));
Packit Service 6f2e62
		strncpy(valstr, &buffer[i], len);
Packit Service 6f2e62
		i += len;
Packit Service 6f2e62
Packit Service 6f2e62
		for(*m = 0;*v && m < pg_dstmac+6;v++) {
Packit Service 6f2e62
			if(*v >= '0' && *v <= '9') {
Packit Service 6f2e62
				*m *= 16;
Packit Service 6f2e62
				*m += *v - '0';
Packit Service 6f2e62
			}
Packit Service 6f2e62
			if(*v >= 'A' && *v <= 'F') {
Packit Service 6f2e62
				*m *= 16;
Packit Service 6f2e62
				*m += *v - 'A' + 10;
Packit Service 6f2e62
			}
Packit Service 6f2e62
			if(*v >= 'a' && *v <= 'f') {
Packit Service 6f2e62
				*m *= 16;
Packit Service 6f2e62
				*m += *v - 'a' + 10;
Packit Service 6f2e62
			}
Packit Service 6f2e62
			if(*v == ':') {
Packit Service 6f2e62
				m++;
Packit Service 6f2e62
				*m = 0;
Packit Service 6f2e62
			}
Packit Service 6f2e62
		}
Packit Service 6f2e62
		sprintf(pg_result, "OK: dstmac");
Packit Service 6f2e62
		return count;
Packit Service 6f2e62
	}
Packit Service 6f2e62
Packit Service 6f2e62
	if (!strcmp(name, "inject") || !strcmp(name, "start") ) {
Packit Service 6f2e62
		MOD_INC_USE_COUNT;
Packit Service 6f2e62
		pg_busy = 1;
Packit Service 6f2e62
		strcpy(pg_result, "Starting");
Packit Service 6f2e62
		pg_inject();
Packit Service 6f2e62
		pg_busy = 0;
Packit Service 6f2e62
		MOD_DEC_USE_COUNT;
Packit Service 6f2e62
		return count;
Packit Service 6f2e62
	}
Packit Service 6f2e62
Packit Service 6f2e62
	sprintf(pg_result, "No such parameter \"%s\"", name);
Packit Service 6f2e62
	return -EINVAL;
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
static int pg_init(void)
Packit Service 6f2e62
{
Packit Service 6f2e62
	printk(version);
Packit Service 6f2e62
	cycles_calibrate();
Packit Service 6f2e62
	if (pg_cpu_speed == 0) {
Packit Service 6f2e62
		printk("pg3: Error: your machine does not have working cycle counter.\n");
Packit Service 6f2e62
		return -EINVAL;
Packit Service 6f2e62
	}
Packit Service 6f2e62
	if(!pg_proc_ent) {
Packit Service 6f2e62
		pg_proc_ent = create_proc_entry("net/pg", 0600, 0);
Packit Service 6f2e62
		if (pg_proc_ent) {
Packit Service 6f2e62
			pg_proc_ent->read_proc = proc_pg_read;
Packit Service 6f2e62
			pg_proc_ent->write_proc = proc_pg_write;
Packit Service 6f2e62
			pg_proc_ent->data = 0;
Packit Service 6f2e62
		}
Packit Service 6f2e62
		pg_busy_proc_ent = create_proc_entry("net/pg_busy", 0, 0);
Packit Service 6f2e62
		if (pg_busy_proc_ent) {
Packit Service 6f2e62
			pg_busy_proc_ent->read_proc = proc_pg_busy_read;
Packit Service 6f2e62
			pg_busy_proc_ent->data = 0;
Packit Service 6f2e62
		}
Packit Service 6f2e62
	}
Packit Service 6f2e62
	return 0;
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
void pg_cleanup(void)
Packit Service 6f2e62
{
Packit Service 6f2e62
	if (pg_proc_ent) {
Packit Service 6f2e62
		remove_proc_entry("net/pg", NULL);
Packit Service 6f2e62
		pg_proc_ent = 0;
Packit Service 6f2e62
		remove_proc_entry("net/pg_busy", NULL);
Packit Service 6f2e62
		pg_busy_proc_ent = 0;
Packit Service 6f2e62
	}
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
module_init(pg_init);
Packit Service 6f2e62
module_exit(pg_cleanup);
Packit Service 6f2e62
Packit Service 6f2e62
Packit Service 6f2e62
#if LINUX_VERSION_CODE > 0x20118
Packit Service 6f2e62
MODULE_AUTHOR("Robert Olsson 
Packit Service 6f2e62
MODULE_DESCRIPTION("Packet Generator tool");
Packit Service 6f2e62
MODULE_PARM(pg_count, "i");
Packit Service 6f2e62
MODULE_PARM(pg_ipg, "i");
Packit Service 6f2e62
MODULE_PARM(pg_cpu_speed, "i");
Packit Service 6f2e62
#endif
Packit Service 6f2e62
Packit Service 6f2e62
/*
Packit Service 6f2e62
 * Local variables:
Packit Service 6f2e62
 * compile-command: "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/include -Wall -Wstrict-prototypes -O2 -c pg3.c"
Packit Service 6f2e62
 * End:
Packit Service 6f2e62
 */